feat(fer-19) : checkHealth sur le PontBasculeService
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Dto\PontBasculeHealth;
|
||||
use App\Dto\PontBasculeReading;
|
||||
use App\Exception\PontBasculeException;
|
||||
use DateTimeImmutable;
|
||||
@@ -28,7 +29,7 @@ final class PontBasculeService
|
||||
$body = $this->getBypassPayload();
|
||||
} else {
|
||||
try {
|
||||
$response = $this->httpClient->request('POST', $this->baseUrl.'/send/dsd');
|
||||
$response = $this->httpClient->request('POST', $this->buildUrl('/send/dsd'));
|
||||
$body = $response->getContent(false);
|
||||
} catch (TransportExceptionInterface $exception) {
|
||||
throw PontBasculeException::transportFailure($exception->getMessage());
|
||||
@@ -44,6 +45,54 @@ final class PontBasculeService
|
||||
);
|
||||
}
|
||||
|
||||
public function checkHealth(): PontBasculeHealth
|
||||
{
|
||||
if ($this->bypass) {
|
||||
return new PontBasculeHealth(
|
||||
healthy: true,
|
||||
ok: true,
|
||||
busy: false,
|
||||
portConnected: true,
|
||||
portError: null,
|
||||
hostname: 'bypass',
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $this->httpClient->request('GET', $this->buildUrl('/health'));
|
||||
$body = $response->getContent(false);
|
||||
} catch (TransportExceptionInterface) {
|
||||
return PontBasculeHealth::unhealthy();
|
||||
}
|
||||
|
||||
$payload = json_decode($body, true);
|
||||
if (!is_array($payload)) {
|
||||
return PontBasculeHealth::unhealthy();
|
||||
}
|
||||
|
||||
$ok = true === ($payload['ok'] ?? null);
|
||||
$busy = true === ($payload['busy'] ?? null);
|
||||
$portConnected = true === ($payload['port_connected'] ?? null);
|
||||
$portError = $payload['port_error'] ?? null;
|
||||
$hostname = $payload['hostname'] ?? null;
|
||||
|
||||
$healthy = $ok && $portConnected && !$busy && null === $portError;
|
||||
|
||||
return new PontBasculeHealth(
|
||||
healthy: $healthy,
|
||||
ok: $ok,
|
||||
busy: $busy,
|
||||
portConnected: $portConnected,
|
||||
portError: is_string($portError) ? $portError : null,
|
||||
hostname: is_string($hostname) ? $hostname : null,
|
||||
);
|
||||
}
|
||||
|
||||
private function buildUrl(string $path): string
|
||||
{
|
||||
return rtrim($this->baseUrl, '/').$path;
|
||||
}
|
||||
|
||||
private function getBypassPayload(): string
|
||||
{
|
||||
return '{"ok":true,"busy":false,"mode":"serial","port":"/dev/ttyUSB0","baudrate":9600,"request_hex":"01 10 39 39 4D 0D 0A","response_hex":"01 02 30 34 30 32 30 30 02 30 31 30 30 31 34 32 30 2E 6B 67 20 02 30 32 30 30 30 30 30 30 2E 6B 67 20 02 30 33 30 30 31 34 32 30 2E 6B 67 20 02 39 39 30 30 31 32 31 0D 0A","response_ascii":"\u0001\u0002040200\u000201001420.kg \u000202000000.kg \u000203001420.kg \u00029900121"}';
|
||||
|
||||
@@ -82,4 +82,103 @@ final class PontBasculeServiceTest extends TestCase
|
||||
|
||||
$service->fetch();
|
||||
}
|
||||
|
||||
public function testCheckHealthBypassIsHealthyWithoutHttpCall(): void
|
||||
{
|
||||
$httpClient = $this->createMock(HttpClientInterface::class);
|
||||
$httpClient->expects(self::never())->method('request');
|
||||
|
||||
$service = new PontBasculeService($httpClient, new PontBasculePayloadDecoder(), 'http://example.test', true);
|
||||
|
||||
$health = $service->checkHealth();
|
||||
|
||||
self::assertTrue($health->isHealthy());
|
||||
}
|
||||
|
||||
public function testCheckHealthHealthyPayload(): void
|
||||
{
|
||||
$service = $this->serviceForHealthBody(json_encode([
|
||||
'ok' => true,
|
||||
'busy' => false,
|
||||
'port_connected' => true,
|
||||
'port_error' => null,
|
||||
'hostname' => 'liot-rasp-ferme-01',
|
||||
], JSON_THROW_ON_ERROR));
|
||||
|
||||
$health = $service->checkHealth();
|
||||
|
||||
self::assertTrue($health->isHealthy());
|
||||
self::assertSame('liot-rasp-ferme-01', $health->getHostname());
|
||||
}
|
||||
|
||||
public function testCheckHealthUnhealthyWhenPortError(): void
|
||||
{
|
||||
$service = $this->serviceForHealthBody(json_encode([
|
||||
'ok' => true,
|
||||
'busy' => false,
|
||||
'port_connected' => true,
|
||||
'port_error' => 'device disconnected',
|
||||
], JSON_THROW_ON_ERROR));
|
||||
|
||||
self::assertFalse($service->checkHealth()->isHealthy());
|
||||
}
|
||||
|
||||
public function testCheckHealthUnhealthyWhenPortNotConnected(): void
|
||||
{
|
||||
$service = $this->serviceForHealthBody(json_encode([
|
||||
'ok' => true,
|
||||
'busy' => false,
|
||||
'port_connected' => false,
|
||||
'port_error' => null,
|
||||
], JSON_THROW_ON_ERROR));
|
||||
|
||||
self::assertFalse($service->checkHealth()->isHealthy());
|
||||
}
|
||||
|
||||
public function testCheckHealthUnhealthyWhenBusy(): void
|
||||
{
|
||||
$service = $this->serviceForHealthBody(json_encode([
|
||||
'ok' => true,
|
||||
'busy' => true,
|
||||
'port_connected' => true,
|
||||
'port_error' => null,
|
||||
], JSON_THROW_ON_ERROR));
|
||||
|
||||
self::assertFalse($service->checkHealth()->isHealthy());
|
||||
}
|
||||
|
||||
public function testCheckHealthUnhealthyOnTransportFailure(): void
|
||||
{
|
||||
$httpClient = $this->createMock(HttpClientInterface::class);
|
||||
$httpClient
|
||||
->expects(self::once())
|
||||
->method('request')
|
||||
->willThrowException($this->createStub(TransportExceptionInterface::class))
|
||||
;
|
||||
|
||||
$service = new PontBasculeService($httpClient, new PontBasculePayloadDecoder(), 'http://example.test', false);
|
||||
|
||||
self::assertFalse($service->checkHealth()->isHealthy());
|
||||
}
|
||||
|
||||
public function testCheckHealthUnhealthyOnInvalidJson(): void
|
||||
{
|
||||
self::assertFalse($this->serviceForHealthBody('not-json')->checkHealth()->isHealthy());
|
||||
}
|
||||
|
||||
private function serviceForHealthBody(string $body): PontBasculeService
|
||||
{
|
||||
$response = $this->createStub(ResponseInterface::class);
|
||||
$response->method('getContent')->with(false)->willReturn($body);
|
||||
|
||||
$httpClient = $this->createMock(HttpClientInterface::class);
|
||||
$httpClient
|
||||
->expects(self::once())
|
||||
->method('request')
|
||||
->with('GET', 'http://example.test/health')
|
||||
->willReturn($response)
|
||||
;
|
||||
|
||||
return new PontBasculeService($httpClient, new PontBasculePayloadDecoder(), 'http://example.test', false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user