Files
crm_ecosplay/tests/Command/CheckServicesCommandTest.php
Serreau Jovann b0060bd831 test: achieve 100% coverage for CheckServicesCommand and update SonarQube config
- Add 26 tests covering all service check types (HTTP, DocuSeal, Vault, Minio, Stripe)
- Include assets/ and templates/ in SonarQube sources
- Ignore php:S4144 globally (interface-imposed duplicate methods)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:24:15 +02:00

411 lines
14 KiB
PHP

<?php
namespace App\Tests\Command;
use App\Command\CheckServicesCommand;
use App\Entity\Service;
use App\Entity\ServiceCategory;
use App\Repository\ServiceRepository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
class CheckServicesCommandTest extends TestCase
{
private ServiceRepository $serviceRepository;
private EntityManagerInterface $em;
private HttpClientInterface $httpClient;
protected function setUp(): void
{
$this->serviceRepository = $this->createStub(ServiceRepository::class);
$this->em = $this->createStub(EntityManagerInterface::class);
$this->httpClient = $this->createStub(HttpClientInterface::class);
}
private function execute(?EntityManagerInterface $em = null): CommandTester
{
$command = new CheckServicesCommand(
$this->serviceRepository,
$em ?? $this->em,
$this->httpClient,
);
$tester = new CommandTester($command);
$tester->execute([]);
return $tester;
}
private function createService(string $name, string $url, string $status = 'up', ?string $externalType = null): Service
{
$category = new ServiceCategory('Test', 'test');
$service = new Service($name, strtolower(str_replace(' ', '-', $name)), $category);
$service->setUrl($url);
$service->setStatus($status);
if (null !== $externalType) {
$service->setExternalType($externalType);
$service->setIsExternal(true);
}
return $service;
}
private function mockQueryReturning(array $services): void
{
$query = $this->createStub(Query::class);
$query->method('getResult')->willReturn($services);
$qb = $this->createStub(QueryBuilder::class);
$qb->method('where')->willReturnSelf();
$qb->method('andWhere')->willReturnSelf();
$qb->method('setParameter')->willReturnSelf();
$qb->method('getQuery')->willReturn($query);
$this->serviceRepository->method('createQueryBuilder')->willReturn($qb);
}
private function mockResponse(int $statusCode, array $json = []): ResponseInterface
{
$response = $this->createStub(ResponseInterface::class);
$response->method('getStatusCode')->willReturn($statusCode);
$response->method('toArray')->willReturn($json);
return $response;
}
public function testNoServicesToCheck(): void
{
$this->mockQueryReturning([]);
$tester = $this->execute();
$this->assertSame(0, $tester->getStatusCode());
$this->assertStringContainsString('Aucun service', $tester->getDisplay());
}
public function testServiceUpViaHttp(): void
{
$service = $this->createService('Web App', 'https://example.com');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturn($this->mockResponse(200));
$tester = $this->execute();
$this->assertSame(0, $tester->getStatusCode());
$this->assertStringContainsString('1 service(s) verifie(s), 0 changement(s)', $tester->getDisplay());
}
public function testServiceDownViaHttp(): void
{
$service = $this->createService('Web App', 'https://example.com');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturn($this->mockResponse(500));
$tester = $this->execute();
$this->assertSame(0, $tester->getStatusCode());
$this->assertStringContainsString('1 service(s) verifie(s), 1 changement(s)', $tester->getDisplay());
$this->assertSame(Service::STATUS_DOWN, $service->getStatus());
}
public function testServiceDegradedViaHttp(): void
{
$service = $this->createService('Web App', 'https://example.com');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturn($this->mockResponse(403));
$this->execute();
$this->assertSame(Service::STATUS_DEGRADED, $service->getStatus());
}
public function testHttpExceptionMarksDown(): void
{
$service = $this->createService('Web App', 'https://example.com');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willThrowException(new \RuntimeException('timeout'));
$this->execute();
$this->assertSame(Service::STATUS_DOWN, $service->getStatus());
}
public function testSkipsSoonStatus(): void
{
$service = $this->createService('Future', 'https://example.com', Service::STATUS_SOON);
$this->mockQueryReturning([$service]);
$tester = $this->execute();
$this->assertSame(0, $tester->getStatusCode());
$this->assertStringContainsString('Skip', $tester->getDisplay());
$this->assertStringContainsString('0 service(s) verifie(s)', $tester->getDisplay());
}
public function testSkipsMaintenanceStatus(): void
{
$service = $this->createService('Maint', 'https://example.com', Service::STATUS_MAINTENANCE);
$this->mockQueryReturning([$service]);
$tester = $this->execute();
$this->assertStringContainsString('Skip', $tester->getDisplay());
}
public function testDocuSealCheckUp(): void
{
$service = $this->createService('DocuSeal', 'https://docuseal.example.com', 'up', 'docuseal');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturn($this->mockResponse(200));
$this->execute();
$this->assertSame(Service::STATUS_UP, $service->getStatus());
}
public function testDocuSealCheckDown(): void
{
$service = $this->createService('DocuSeal', 'https://docuseal.example.com', 'up', 'docuseal');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturn($this->mockResponse(503));
$this->execute();
$this->assertSame(Service::STATUS_DOWN, $service->getStatus());
}
public function testDocuSealCheckException(): void
{
$service = $this->createService('DocuSeal', 'https://docuseal.example.com', 'up', 'docuseal');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willThrowException(new \RuntimeException('fail'));
$this->execute();
$this->assertSame(Service::STATUS_DOWN, $service->getStatus());
}
public function testVaultCheckUp(): void
{
$service = $this->createService('Vault', 'https://vault.example.com', 'up', 'vault');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturn($this->mockResponse(200));
$this->execute();
$this->assertSame(Service::STATUS_UP, $service->getStatus());
}
public function testVaultCheckDegraded(): void
{
$service = $this->createService('Vault', 'https://vault.example.com', 'up', 'vault');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturn($this->mockResponse(429));
$this->execute();
$this->assertSame(Service::STATUS_DEGRADED, $service->getStatus());
}
public function testVaultCheckDown(): void
{
$service = $this->createService('Vault', 'https://vault.example.com', 'up', 'vault');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturn($this->mockResponse(503));
$this->execute();
$this->assertSame(Service::STATUS_DOWN, $service->getStatus());
}
public function testVaultCheckException(): void
{
$service = $this->createService('Vault', 'https://vault.example.com', 'up', 'vault');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willThrowException(new \RuntimeException('fail'));
$this->execute();
$this->assertSame(Service::STATUS_DOWN, $service->getStatus());
}
public function testMinioCheckUp(): void
{
$service = $this->createService('Minio', 'https://minio.example.com', 'up', 'minio');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturn($this->mockResponse(200));
$this->execute();
$this->assertSame(Service::STATUS_UP, $service->getStatus());
}
public function testMinioCheckDown(): void
{
$service = $this->createService('Minio', 'https://minio.example.com', 'up', 'minio');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturn($this->mockResponse(503));
$this->execute();
$this->assertSame(Service::STATUS_DOWN, $service->getStatus());
}
public function testMinioCheckException(): void
{
$service = $this->createService('Minio', 'https://minio.example.com', 'up', 'minio');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willThrowException(new \RuntimeException('fail'));
$this->execute();
$this->assertSame(Service::STATUS_DOWN, $service->getStatus());
}
public function testStripeCheckUpdatesStatus(): void
{
$service = $this->createService('Stripe', 'https://stripe.com', 'up', 'stripe');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturnCallback(function (string $method, string $url) {
if (str_contains($url, 'status.stripe.com')) {
return $this->mockResponse(200, [
'status' => ['indicator' => 'major', 'description' => 'Major outage'],
]);
}
return $this->mockResponse(200);
});
$this->execute();
$this->assertSame(Service::STATUS_DOWN, $service->getStatus());
}
public function testStripeCheckMinor(): void
{
$service = $this->createService('Stripe', 'https://stripe.com', 'up', 'stripe');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturnCallback(function (string $method, string $url) {
if (str_contains($url, 'status.stripe.com')) {
return $this->mockResponse(200, [
'status' => ['indicator' => 'minor', 'description' => 'Minor issue'],
]);
}
return $this->mockResponse(200);
});
$this->execute();
$this->assertSame(Service::STATUS_DEGRADED, $service->getStatus());
}
public function testStripeCheckNone(): void
{
$service = $this->createService('Stripe', 'https://stripe.com', 'up', 'stripe');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturnCallback(function (string $method, string $url) {
if (str_contains($url, 'status.stripe.com')) {
return $this->mockResponse(200, [
'status' => ['indicator' => 'none', 'description' => 'All good'],
]);
}
return $this->mockResponse(200);
});
$this->execute();
$this->assertSame(Service::STATUS_UP, $service->getStatus());
}
public function testStripeCheckCritical(): void
{
$service = $this->createService('Stripe', 'https://stripe.com', 'up', 'stripe');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturnCallback(function (string $method, string $url) {
if (str_contains($url, 'status.stripe.com')) {
return $this->mockResponse(200, [
'status' => ['indicator' => 'critical', 'description' => 'Critical outage'],
]);
}
return $this->mockResponse(200);
});
$this->execute();
$this->assertSame(Service::STATUS_DOWN, $service->getStatus());
}
public function testStripeCheckUnknownIndicator(): void
{
$service = $this->createService('Stripe', 'https://stripe.com', 'up', 'stripe');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturnCallback(function (string $method, string $url) {
if (str_contains($url, 'status.stripe.com')) {
return $this->mockResponse(200, [
'status' => ['indicator' => 'unknown_value', 'description' => 'Unknown'],
]);
}
return $this->mockResponse(200);
});
$this->execute();
$this->assertSame(Service::STATUS_UP, $service->getStatus());
}
public function testStripeCheckException(): void
{
$service = $this->createService('Stripe', 'https://stripe.com', 'up', 'stripe');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willThrowException(new \RuntimeException('network error'));
$tester = $this->execute();
$this->assertStringContainsString('Impossible de verifier', $tester->getDisplay());
}
public function testFlushCalledAfterChecks(): void
{
$service = $this->createService('Web App', 'https://example.com');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturn($this->mockResponse(200));
$em = $this->createMock(EntityManagerInterface::class);
$em->expects($this->once())->method('flush');
$this->execute($em);
}
public function testServiceStatusChangeMessage(): void
{
$service = $this->createService('API', 'https://api.example.com');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturn($this->mockResponse(500));
$tester = $this->execute();
$this->assertStringContainsString('Auto-detection', $tester->getDisplay());
$this->assertStringContainsString('up -> down', $tester->getDisplay());
}
public function testHttpRedirect3xx(): void
{
$service = $this->createService('Redirect', 'https://example.com');
$this->mockQueryReturning([$service]);
$this->httpClient->method('request')->willReturn($this->mockResponse(301));
$this->execute();
$this->assertSame(Service::STATUS_UP, $service->getStatus());
}
}