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:
@@ -1,7 +1,7 @@
|
|||||||
sonar.projectKey=crm-ecosplay
|
sonar.projectKey=crm-ecosplay
|
||||||
sonar.projectName=CRM Ecosplay
|
sonar.projectName=CRM Ecosplay
|
||||||
|
|
||||||
sonar.sources=src
|
sonar.sources=src,assets,templates
|
||||||
sonar.tests=tests
|
sonar.tests=tests
|
||||||
|
|
||||||
sonar.language=php
|
sonar.language=php
|
||||||
@@ -19,6 +19,11 @@ sonar.php.tests.reportPath=var/reports/phpunit.xml
|
|||||||
# Duplication exclusions
|
# Duplication exclusions
|
||||||
sonar.cpd.exclusions=migrations/**
|
sonar.cpd.exclusions=migrations/**
|
||||||
|
|
||||||
|
# Global rule ignores
|
||||||
|
sonar.issue.ignore.multicriteria=e1
|
||||||
|
sonar.issue.ignore.multicriteria.e1.ruleKey=php:S4144
|
||||||
|
sonar.issue.ignore.multicriteria.e1.resourceKey=**/*.php
|
||||||
|
|
||||||
# ─── Rapports externes ────────────────────────────
|
# ─── Rapports externes ────────────────────────────
|
||||||
sonar.php.phpstan.reportPaths=var/reports/phpstan-report.json
|
sonar.php.phpstan.reportPaths=var/reports/phpstan-report.json
|
||||||
sonar.javascript.eslint.reportPaths=var/reports/eslint-report.json
|
sonar.javascript.eslint.reportPaths=var/reports/eslint-report.json
|
||||||
|
|||||||
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