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>
This commit is contained in:
410
tests/Command/CheckServicesCommandTest.php
Normal file
410
tests/Command/CheckServicesCommandTest.php
Normal file
@@ -0,0 +1,410 @@
|
||||
<?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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user