major refactor

- add request status to search instance API
- use JSend-type response in elixForms clients
- readjust namespaces
- add more unit tests (manual HTTP requests too)
This commit is contained in:
2026-07-24 14:56:25 +02:00
parent ef53ee8364
commit 33ff4d9577
11 changed files with 315 additions and 129 deletions
+5 -5
View File
@@ -12,9 +12,9 @@ use Api\Core\RateLimiter\RateLimiterInterface;
use Api\Core\RateLimiter\FileRateLimiter; use Api\Core\RateLimiter\FileRateLimiter;
use Api\Core\RateLimiter\InMemoryRateLimiter; use Api\Core\RateLimiter\InMemoryRateLimiter;
use Api\Core\Log\LoggerFactory; use Api\Core\Log\LoggerFactory;
use ElixForms\ElixFormsClient; use ElixForms\Clients\ElixFormsApiClient;
use ElixForms\Auth\ElixFormsApiClient; use ElixForms\Clients\ElixFormsAuthenticationClient;
use ElixForms\Auth\ElixFormsAuthenticationClient; use ElixForms\Clients\ElixFormsGenericClient;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
$container = new Container(); $container = new Container();
@@ -63,10 +63,10 @@ $container->singleton(LoggerInterface::class, function($c) {
}); });
// ElixForms client binding // ElixForms client binding
$container->singleton(ElixFormsClient::class, function($c) { $container->singleton(ElixFormsGenericClient::class, function($c) {
$config = $c->make(Config::class); $config = $c->make(Config::class);
$baseUrl = $config->get('elixforms_api_base_url'); $baseUrl = $config->get('elixforms_api_base_url');
return new ElixFormsClient($baseUrl); return new ElixFormsGenericClient($baseUrl, null);
}); });
$container->singleton(ElixFormsAuthenticationClient::class, function($c) { $container->singleton(ElixFormsAuthenticationClient::class, function($c) {
-19
View File
@@ -1,19 +0,0 @@
@term=MA
GET http://localhost:8000/api/dipendenti/cerca?term={{term}}
Authorization: Basic elixforms_ws:password123
X-API-Key: myApiAccessToken
###
@term=ID
GET http://localhost:8000/api/contratti/cerca?term={{term}}&cod_fis=MMMPPL74T17E463A
Authorization: Basic elixforms_ws:password123
X-API-Key: myApiAccessToken
###
@term=ID
GET http://localhost:8000/contratti/cerca?term={{term}}
+42 -9
View File
@@ -4,9 +4,8 @@ namespace Api\Controllers\V1;
use Api\Core\Config; use Api\Core\Config;
use Api\Core\Request; use Api\Core\Request;
use Api\Core\Response; use Api\Core\Response;
use ElixForms\Auth\ElixFormsApiClient; use ElixForms\Clients\ElixFormsApiClient;
use ElixForms\Auth\ElixFormsAuthenticationClient; use ElixForms\Clients\ElixFormsAuthenticationClient;
use ElixForms\Exceptions\ElixFormsException;
class ElixFormsController class ElixFormsController
{ {
@@ -30,11 +29,15 @@ class ElixFormsController
$moduleTag = $this->requiredString($query, 'moduleTag'); $moduleTag = $this->requiredString($query, 'moduleTag');
$fieldName = $this->requiredString($query, 'fieldName'); $fieldName = $this->requiredString($query, 'fieldName');
$fieldValue = $this->requiredString($query, 'fieldValue'); $fieldValue = $this->requiredString($query, 'fieldValue');
$requestStatuses = $this->requiredString($query, 'requestStatuses');
$exportGroup = $this->optionalNonEmptyString($query, 'exportGroup', 'API'); $exportGroup = $this->optionalNonEmptyString($query, 'exportGroup', 'API');
if ($moduleTag === null || $fieldName === null || $fieldValue === null || $exportGroup === null) { if ($moduleTag === null || $fieldName === null || $fieldValue === null || $exportGroup === null) {
return $res->json([ return $res->json([
'error' => 'moduleTag, fieldName e fieldValue sono obbligatori; exportGroup, se specificato, deve essere una stringa non vuota.' 'status' => 'fail',
'data' => [
'parameters' => 'moduleTag, fieldName e fieldValue sono obbligatori; exportGroup, se specificato, deve essere una stringa non vuota.',
],
], 400); ], 400);
} }
@@ -42,11 +45,31 @@ class ElixFormsController
$password = $this->config->secret('elixforms_api_password'); $password = $this->config->secret('elixforms_api_password');
if (!\is_string($username) || trim($username) === '' || !\is_string($password) || $password === '') { if (!\is_string($username) || trim($username) === '' || !\is_string($password) || $password === '') {
throw new ElixFormsException('Credenziali elixForms non configurate.'); return $res->json([
'status' => 'error',
'message' => 'Credenziali elixForms non configurate.',
'code' => 500,
], 500);
} }
$token = $this->authenticationClient->login($username, $password); $login = $this->authenticationClient->login($username, $password);
$instances = $this->apiClient->lookupByStatus($moduleTag, $token, $username); if ($login['status'] !== 'success') {
return $this->respondWithJSendFailure($res, $login);
}
$token = $login['data']['authToken'];
$instancesResponse = $this->apiClient->lookupByStatus(
$moduleTag,
$token,
$username,
$requestStatuses
);
if ($instancesResponse['status'] !== 'success') {
return $this->respondWithJSendFailure($res, $instancesResponse);
}
$instances = $instancesResponse['data'];
$matchingInstances = []; $matchingInstances = [];
foreach ($instances as $instance) { foreach ($instances as $instance) {
@@ -59,13 +82,18 @@ class ElixFormsController
continue; continue;
} }
$exportTags = $this->apiClient->getExportTags( $exportTagsResponse = $this->apiClient->getExportTags(
$requestId, $requestId,
$moduleTag, $moduleTag,
$token, $token,
$username, $username,
$exportGroup $exportGroup
); );
if ($exportTagsResponse['status'] !== 'success') {
return $this->respondWithJSendFailure($res, $exportTagsResponse);
}
$exportTags = $exportTagsResponse['data'];
$exportTagsByName = array_column($exportTags, null, 'name'); $exportTagsByName = array_column($exportTags, null, 'name');
if (!\array_key_exists($fieldName, $exportTagsByName)) { if (!\array_key_exists($fieldName, $exportTagsByName)) {
@@ -80,7 +108,12 @@ class ElixFormsController
} }
} }
return $res->json($matchingInstances); return $res->json(['status' => 'success', 'data' => $matchingInstances]);
}
private function respondWithJSendFailure(Response $response, array $payload)
{
return $response->json($payload, $payload['status'] === 'fail' ? 400 : 502);
} }
private function requiredString(array $values, string $key): ?string private function requiredString(array $values, string $key): ?string
@@ -1,8 +1,8 @@
<?php <?php
namespace ElixForms\Auth; namespace ElixForms\Clients;
use Api\Core\HttpClient; use Api\Core\HttpClient;
use ElixForms\Exceptions\ElixFormsException; use ElixForms\Enums\ElixFormsRequestStatus;
class ElixFormsApiClient class ElixFormsApiClient
{ {
@@ -17,39 +17,46 @@ class ElixFormsApiClient
/** /**
* Restituisce le istanze del modulo, opzionalmente filtrate per stato. * Restituisce le istanze del modulo, opzionalmente filtrate per stato.
* I flag di ElixFormsRequestStatus possono essere combinati con l'operatore |. * Gli stati sono separati da virgole e diventano query parameter requestStatus ripetuti.
* *
* @return array<int,array<string,mixed>> * @return array{status:string,data?:array<int,array<string,mixed>>,message?:string,code?:int}
*/ */
public function lookupByStatus( public function lookupByStatus(
string $moduleTag, string $moduleTag,
string $authToken, string $authToken,
string $username, string $username,
?int $status = null ?string $requestStatuses = null
): array ): array
{ {
$queryParts = []; $queryParts = [];
if ($status !== null) { try {
foreach (ElixFormsRequestStatus::toApiValues($status) as $statusValue) { foreach (ElixFormsRequestStatus::fromQueryParameter($requestStatuses) as $statusValue) {
$queryParts[] = 'requestStatus=' . rawurlencode($statusValue); $queryParts[] = 'requestStatus=' . rawurlencode($statusValue);
} }
} catch (\InvalidArgumentException $exception) {
return $this->fail(['requestStatuses' => $exception->getMessage()]);
} }
$queryParts[] = 'moduleTag=' . rawurlencode($moduleTag); $queryParts[] = 'moduleTag=' . rawurlencode($moduleTag);
$url = "{$this->baseUrl}/api/request/lookup/by-status?" . implode('&', $queryParts); $url = "{$this->baseUrl}/api/request/lookup/by-status?" . implode('&', $queryParts);
$payload = $this->getJsonAsArray($url, $authToken, $username, 'LookupByStatus'); $payload = $this->getJsonAsArray($url, $authToken, $username, 'LookupByStatus');
if ($payload['status'] !== 'success') {
return $payload;
}
$payload = $payload['data'];
$requests = $payload['value']['requests'] ?? []; $requests = $payload['value']['requests'] ?? [];
if (!\is_array($requests)) { if (!\is_array($requests)) {
throw new ElixFormsException('Risposta LookupByStatus non valida: requests deve essere un array.'); return $this->error('Risposta LookupByStatus non valida: requests deve essere un array.');
} }
return array_values($requests); return $this->success(array_values($requests));
} }
/** /**
* @param int|string $requestId * @param int|string $requestId
* @return array<int,array{name?:mixed,value?:mixed}> * @return array{status:string,data?:array<int,array{name?:mixed,value?:mixed}>,message?:string,code?:int}
*/ */
public function getExportTags( public function getExportTags(
$requestId, $requestId,
@@ -61,7 +68,7 @@ class ElixFormsApiClient
{ {
$exportGroup = trim($exportGroup); $exportGroup = trim($exportGroup);
if ($exportGroup === '') { if ($exportGroup === '') {
throw new \InvalidArgumentException('exportGroup deve essere una stringa non vuota.'); return $this->fail(['exportGroup' => 'deve essere una stringa non vuota.']);
} }
$url = \sprintf( $url = \sprintf(
@@ -72,13 +79,18 @@ class ElixFormsApiClient
rawurlencode($exportGroup) rawurlencode($exportGroup)
); );
$payload = $this->getJsonAsArray($url, $authToken, $username, 'GetExportTags'); $payload = $this->getJsonAsArray($url, $authToken, $username, 'GetExportTags');
if ($payload['status'] !== 'success') {
return $payload;
}
$payload = $payload['data'];
$exportTags = $payload['value']['exportTags'] ?? []; $exportTags = $payload['value']['exportTags'] ?? [];
if (!\is_array($exportTags)) { if (!\is_array($exportTags)) {
throw new ElixFormsException('Risposta GetExportTags non valida: exportTags deve essere un array.'); return $this->error('Risposta GetExportTags non valida: exportTags deve essere un array.');
} }
return array_values($exportTags); return $this->success(array_values($exportTags));
} }
private function getJsonAsArray( private function getJsonAsArray(
@@ -94,13 +106,9 @@ class ElixFormsApiClient
'x-api-username' => $username, 'x-api-username' => $username,
]); ]);
$status = $response['status'] ?? 500; $status = (int) ($response['status'] ?? 500);
if ($status !== 200) { if ($status !== 200) {
throw new ElixFormsException(\sprintf( return $this->error(\sprintf('Errore durante %s.', $operation), $status);
'Errore durante %s. HTTP Status: %d',
$operation,
$status
));
} }
$payload = $response['json'] ?? null; $payload = $response['json'] ?? null;
@@ -111,22 +119,33 @@ class ElixFormsApiClient
} }
if (!\is_array($payload) || $jsonError !== JSON_ERROR_NONE) { if (!\is_array($payload) || $jsonError !== JSON_ERROR_NONE) {
throw new ElixFormsException(\sprintf( return $this->error(\sprintf('Risposta non valida da %s: atteso JSON.', $operation));
'Risposta non valida da %s: atteso JSON.',
$operation
));
} }
$globalStatus = $payload['value']['globalStatus'] ?? null; $globalStatus = $payload['value']['globalStatus'] ?? null;
if ($globalStatus === 'ERROR') { if ($globalStatus === 'ERROR') {
$description = $payload['value']['description'] ?? 'errore non specificato'; $description = $payload['value']['description'] ?? 'errore non specificato';
throw new ElixFormsException(\sprintf( return $this->fail([
'%s ha restituito un errore: %s', 'operation' => $operation,
$operation, 'description' => $description,
$description ]);
));
} }
return $payload; return $this->success($payload);
}
private function success(array $data): array
{
return ['status' => 'success', 'data' => $data];
}
private function fail(array $data): array
{
return ['status' => 'fail', 'data' => $data];
}
private function error(string $message, int $code = 502): array
{
return ['status' => 'error', 'message' => $message, 'code' => $code];
} }
} }
@@ -1,7 +1,6 @@
<?php <?php
namespace ElixForms\Auth; namespace ElixForms\Clients;
use ElixForms\Exceptions\ElixFormsException;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Exception\GuzzleException;
@@ -19,10 +18,9 @@ class ElixFormsAuthenticationClient {
* *
* @param string $username * @param string $username
* @param string $password * @param string $password
* @return string Il token di autenticazione (authToken) * @return array{status:string,data?:array{authToken:string},message?:string,code?:int}
* @throws ElixFormsException Se le credenziali sono errate o c'è un errore server
*/ */
public function login(string $username, string $password): string { public function login(string $username, string $password): array {
$url = "{$this->baseUrl}/services/api/authentication/login/v1"; $url = "{$this->baseUrl}/services/api/authentication/login/v1";
try { try {
@@ -39,23 +37,23 @@ class ElixFormsAuthenticationClient {
$status = $response->getStatusCode(); $status = $response->getStatusCode();
if ($status !== 200) { if ($status !== 200) {
throw new ElixFormsException("Errore durante il login elixForms. HTTP Status: " . $status); return $this->error('Errore durante il login elixForms.', $status);
} }
$body = $response->getBody()->getContents(); $body = $response->getBody()->getContents();
$json = json_decode($body, true); $json = json_decode($body, true);
if (json_last_error() !== JSON_ERROR_NONE || empty($json)) { if (json_last_error() !== JSON_ERROR_NONE || empty($json)) {
throw new ElixFormsException("Risposta non valida dal server elixForms: atteso JSON."); return $this->error('Risposta non valida dal server elixForms: atteso JSON.');
} }
if (isset($json['value']['authToken'])) { if (isset($json['value']['authToken'])) {
return $json['value']['authToken']; return $this->success(['authToken' => $json['value']['authToken']]);
} }
throw new ElixFormsException("authToken non trovato nella risposta del login elixForms."); return $this->fail(['authToken' => 'non trovato nella risposta del login elixForms.']);
} catch (GuzzleException $e) { } catch (GuzzleException $e) {
throw new ElixFormsException("Errore di connessione al server elixForms: " . $e->getMessage(), 0, $e); return $this->error('Errore di connessione al server elixForms.');
} }
} }
@@ -64,10 +62,9 @@ class ElixFormsAuthenticationClient {
* *
* @param string $username * @param string $username
* @param string $token * @param string $token
* @return bool True se il logout ha successo * @return array{status:string,data?:array{loggedOut:bool},message?:string,code?:int}
* @throws ElixFormsException Se c'è un errore durante il logout
*/ */
public function logout(string $username, string $token): bool { public function logout(string $username, string $token): array {
$url = "{$this->baseUrl}/services/api/authentication/" . urlencode($username) . '/logout/v1'; $url = "{$this->baseUrl}/services/api/authentication/" . urlencode($username) . '/logout/v1';
try { try {
@@ -80,12 +77,24 @@ class ElixFormsAuthenticationClient {
$status = $response->getStatusCode(); $status = $response->getStatusCode();
if ($status !== 200) { if ($status !== 200) {
throw new ElixFormsException("Errore durante il logout elixForms. HTTP Status: " . $status); return $this->error('Errore durante il logout elixForms.', $status);
} }
return true; return $this->success(['loggedOut' => true]);
} catch (GuzzleException $e) { } catch (GuzzleException $e) {
throw new ElixFormsException("Errore di connessione al server elixForms: " . $e->getMessage(), 0, $e); return $this->error('Errore di connessione al server elixForms.');
} }
} }
private function success(array $data): array {
return ['status' => 'success', 'data' => $data];
}
private function fail(array $data): array {
return ['status' => 'fail', 'data' => $data];
}
private function error(string $message, int $code = 502): array {
return ['status' => 'error', 'message' => $message, 'code' => $code];
}
} }
@@ -1,12 +1,11 @@
<?php <?php
namespace ElixForms; namespace ElixForms\Clients;
use ElixForms\Auth\ElixFormsAuthenticationClient as AuthClient; use ElixForms\Clients\ElixFormsAuthenticationClient;
use ElixForms\Exceptions\ElixFormsException;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Exception\GuzzleException;
class ElixFormsClient class ElixFormsGenericClient
{ {
private string $baseUrl; private string $baseUrl;
private Client $httpClient; private Client $httpClient;
@@ -17,9 +16,9 @@ class ElixFormsClient
$this->httpClient = $httpClient ?? new Client(['timeout' => 10.0, 'http_errors' => false]); $this->httpClient = $httpClient ?? new Client(['timeout' => 10.0, 'http_errors' => false]);
} }
public function auth(): AuthClient public function auth(): ElixFormsAuthenticationClient
{ {
return new AuthClient($this->baseUrl, $this->httpClient); return new ElixFormsAuthenticationClient($this->baseUrl, $this->httpClient);
} }
public function request(string $method, string $path, ?array $body, array $headers = []): array public function request(string $method, string $path, ?array $body, array $headers = []): array
@@ -38,15 +37,31 @@ class ElixFormsClient
$contentType = $response->getHeaderLine('Content-Type'); $contentType = $response->getHeaderLine('Content-Type');
$isJson = stripos($contentType, 'application/json') !== false; $isJson = stripos($contentType, 'application/json') !== false;
return [ $data = [
'status' => $status, 'status' => $status,
'headers' => $response->getHeaders(), 'headers' => $response->getHeaders(),
'body' => $bodyRaw, 'body' => $bodyRaw,
'is_json' => $isJson, 'is_json' => $isJson,
'json' => $isJson ? json_decode($bodyRaw, true) : null, 'json' => $isJson ? json_decode($bodyRaw, true) : null,
]; ];
} catch (GuzzleException $e) {
throw new ElixFormsException('Errore di connessione al server elixForms: ' . $e->getMessage(), 0, $e); if ($status < 200 || $status >= 300) {
return $this->error('Richiesta a elixForms non riuscita.', $status);
} }
return $this->success($data);
} catch (GuzzleException $e) {
return $this->error('Errore di connessione al server elixForms.');
}
}
private function success(array $data): array
{
return ['status' => 'success', 'data' => $data];
}
private function error(string $message, int $code = 502): array
{
return ['status' => 'error', 'message' => $message, 'code' => $code];
} }
} }
@@ -1,5 +1,5 @@
<?php <?php
namespace ElixForms\Auth; namespace ElixForms\Enums;
use InvalidArgumentException; use InvalidArgumentException;
@@ -28,7 +28,7 @@ final class ElixFormsRequestStatus
/** /**
* @return array<int,string> * @return array<int,string>
*/ */
public static function toApiValues(int $status): array public static function toApiValues(?int $status = self::ALL): array
{ {
if ($status <= 0 || ($status & ~self::ALL) !== 0) { if ($status <= 0 || ($status & ~self::ALL) !== 0) {
throw new InvalidArgumentException('La combinazione di stati elixForms non è valida.'); throw new InvalidArgumentException('La combinazione di stati elixForms non è valida.');
@@ -43,4 +43,31 @@ final class ElixFormsRequestStatus
return $values; return $values;
} }
/**
* @return array<int,string>
*/
public static function fromQueryParameter(?string $requestStatuses): array
{
if ($requestStatuses === null || trim($requestStatuses) === '') {
return [];
}
$allowedValues = array_values(self::API_VALUES);
$statuses = [];
foreach (explode(',', $requestStatuses) as $requestStatus) {
$requestStatus = trim($requestStatus);
if ($requestStatus === '') {
continue;
}
if (!in_array($requestStatus, $allowedValues, true)) {
throw new InvalidArgumentException('Lo stato elixForms richiesto non è valido.');
}
$statuses[] = $requestStatus;
}
return array_values(array_unique($statuses));
}
} }
+17
View File
@@ -0,0 +1,17 @@
# Sample requests to try out authorization logic
###
# Authorization OK
@term=MA
GET http://localhost:8000/api/dipendenti/cerca?term={{term}}
Authorization: Basic elixforms_ws:password123
X-API-Key: myApiAccessToken
###
# Should return 401 Unauthorized
@term=MA
GET http://localhost:8000/api/dipendenti/cerca?term={{term}}
@@ -0,0 +1,26 @@
# Sample requests to trigger web service
###
# TAG not found
GET http://localhost:8000/elixforms/instances/search?moduleTag=ANTANI&fieldName=responsabileScientifico.codiceFiscale&fieldValue=MMM
###
# No data found (choose a TAG with very few instances...)
GET http://localhost:8000/elixforms/instances/search?moduleTag=RequestForm_EDILIZIA_RDA_MANUTENZIONE&fieldName=responsabileScientifico.codiceFiscale&fieldValue=MMM
###
# With one status
GET http://localhost:8000/elixforms/instances/search?requestStatuses=PROCESSED&moduleTag=RequestForm_EDILIZIA_RDA_MANUTENZIONE&fieldName=responsabileScientifico.codiceFiscale&fieldValue=MMM
###
# With two statuses (comma-separated)
GET http://localhost:8000/elixforms/instances/search?requestStatuses=PROCESSED,SUBMITTED&moduleTag=RequestForm_EDILIZIA_RDA_MANUTENZIONE&fieldName=responsabileScientifico.codiceFiscale&fieldValue=MMM
###
# With wrong status
GET http://localhost:8000/elixforms/instances/search?requestStatuses=UNKNOWN&moduleTag=RequestForm_EDILIZIA_RDA_MANUTENZIONE&fieldName=responsabileScientifico.codiceFiscale&fieldValue=MMM
+67 -16
View File
@@ -2,8 +2,7 @@
namespace Tests\Unit; namespace Tests\Unit;
use Api\Core\HttpClient; use Api\Core\HttpClient;
use ElixForms\Auth\ElixFormsApiClient; use ElixForms\Clients\ElixFormsApiClient;
use ElixForms\Auth\ElixFormsRequestStatus;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
final class ElixFormsApiClientTest extends TestCase final class ElixFormsApiClientTest extends TestCase
@@ -32,16 +31,17 @@ final class ElixFormsApiClientTest extends TestCase
}; };
$client = new ElixFormsApiClient('https://example.test', $httpClient); $client = new ElixFormsApiClient('https://example.test', $httpClient);
$requests = $client->lookupByStatus('MODULO TEST', 'token', 'user'); $response = $client->lookupByStatus('MODULO TEST', 'token', 'user');
self::assertSame([['requestId' => 123]], $requests); self::assertSame('success', $response['status']);
self::assertSame([['requestId' => 123]], $response['data']);
self::assertStringNotContainsString('requestStatus=', $httpClient->url); self::assertStringNotContainsString('requestStatus=', $httpClient->url);
self::assertStringContainsString('moduleTag=MODULO%20TEST', $httpClient->url); self::assertStringContainsString('moduleTag=MODULO%20TEST', $httpClient->url);
self::assertSame('Bearer token', $httpClient->headers['Authorization']); self::assertSame('Bearer token', $httpClient->headers['Authorization']);
self::assertSame('user', $httpClient->headers['x-api-username']); self::assertSame('user', $httpClient->headers['x-api-username']);
} }
public function testLookupByStatusExpandsCombinedFlags(): void public function testLookupByStatusExpandsCommaSeparatedStatuses(): void
{ {
$httpClient = new class extends HttpClient { $httpClient = new class extends HttpClient {
public string $url = ''; public string $url = '';
@@ -67,7 +67,7 @@ final class ElixFormsApiClientTest extends TestCase
'MODULO', 'MODULO',
'token', 'token',
'user', 'user',
ElixFormsRequestStatus::IN_PROGRESS | ElixFormsRequestStatus::PROCESSED 'IN_PROGRESS, PROCESSED'
); );
self::assertStringContainsString('requestStatus=IN_PROGRESS', $httpClient->url); self::assertStringContainsString('requestStatus=IN_PROGRESS', $httpClient->url);
@@ -75,11 +75,39 @@ final class ElixFormsApiClientTest extends TestCase
self::assertStringContainsString('requestStatus=PROCESSED', $httpClient->url); self::assertStringContainsString('requestStatus=PROCESSED', $httpClient->url);
} }
public function testRequestStatusRejectsUnknownFlags(): void public function testLookupByStatusOmitsStatusesWhenTheValueIsEmpty(): void
{ {
$this->expectException(\InvalidArgumentException::class); $httpClient = new class extends HttpClient {
public string $url = '';
ElixFormsRequestStatus::toApiValues(8); public function get(string $url, array $headers = [])
{
$this->url = $url;
return [
'status' => 200,
'json' => ['value' => ['globalStatus' => 'OK', 'requests' => []]],
];
}
};
$client = new ElixFormsApiClient('https://example.test', $httpClient);
$client->lookupByStatus('MODULO', 'token', 'user', ' ');
self::assertStringNotContainsString('requestStatus=', $httpClient->url);
}
public function testLookupByStatusReturnsFailForAnUnknownStatus(): void
{
$httpClient = new HttpClient();
$client = new ElixFormsApiClient('https://example.test', $httpClient);
$response = $client->lookupByStatus('MODULO', 'token', 'user', 'UNKNOWN');
self::assertSame([
'status' => 'fail',
'data' => ['requestStatuses' => 'Lo stato elixForms richiesto non è valido.'],
], $response);
} }
public function testGetExportTagsSupportsVendorJsonContentTypeResponses(): void public function testGetExportTagsSupportsVendorJsonContentTypeResponses(): void
@@ -107,14 +135,15 @@ final class ElixFormsApiClientTest extends TestCase
}; };
$client = new ElixFormsApiClient('https://example.test/', $httpClient); $client = new ElixFormsApiClient('https://example.test/', $httpClient);
$tags = $client->getExportTags(42, 'MODULO', 'token', 'user'); $response = $client->getExportTags(42, 'MODULO', 'token', 'user');
self::assertSame('success', $response['status']);
self::assertSame( self::assertSame(
[['name' => 'contratto.id', 'value' => 'ABC-123']], [['name' => 'contratto.id', 'value' => 'ABC-123']],
$tags $response['data']
); );
self::assertSame( self::assertSame(
'https://example.test/eF/services/api/request/42/view/_DEFAULT/exportTags/get/v1?moduleTag=MODULO&exportGroup=API', 'https://example.test/services/api/request/42/view/_DEFAULT/exportTags/get/v1?moduleTag=MODULO&exportGroup=API',
$httpClient->url $httpClient->url
); );
} }
@@ -146,12 +175,34 @@ final class ElixFormsApiClientTest extends TestCase
self::assertStringContainsString('exportGroup=REPORT%20ORE', $httpClient->url); self::assertStringContainsString('exportGroup=REPORT%20ORE', $httpClient->url);
} }
public function testGetExportTagsRejectsAnEmptyExportGroup(): void public function testGetExportTagsReturnsFailForAnEmptyExportGroup(): void
{ {
$this->expectException(\InvalidArgumentException::class);
$httpClient = new HttpClient(); $httpClient = new HttpClient();
$client = new ElixFormsApiClient('https://example.test', $httpClient); $client = new ElixFormsApiClient('https://example.test', $httpClient);
$client->getExportTags(42, 'MODULO', 'token', 'user', ' '); $response = $client->getExportTags(42, 'MODULO', 'token', 'user', ' ');
self::assertSame([
'status' => 'fail',
'data' => ['exportGroup' => 'deve essere una stringa non vuota.'],
], $response);
}
public function testLookupByStatusReturnsErrorForAnUnsuccessfulHttpResponse(): void
{
$httpClient = new class extends HttpClient {
public function get(string $url, array $headers = [])
{
return ['status' => 503];
}
};
$client = new ElixFormsApiClient('https://example.test', $httpClient);
$response = $client->lookupByStatus('MODULO', 'token', 'user');
self::assertSame([
'status' => 'error',
'message' => 'Errore durante LookupByStatus.',
'code' => 503,
], $response);
} }
} }
+17 -9
View File
@@ -5,8 +5,8 @@ use Api\Controllers\V1\ElixFormsController;
use Api\Core\Config; use Api\Core\Config;
use Api\Core\Request; use Api\Core\Request;
use Api\Core\Response; use Api\Core\Response;
use ElixForms\Auth\ElixFormsApiClient; use ElixForms\Clients\ElixFormsApiClient;
use ElixForms\Auth\ElixFormsAuthenticationClient; use ElixForms\Clients\ElixFormsAuthenticationClient;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
final class ElixFormsControllerTest extends TestCase final class ElixFormsControllerTest extends TestCase
@@ -18,9 +18,9 @@ final class ElixFormsControllerTest extends TestCase
{ {
} }
public function login(string $username, string $password): string public function login(string $username, string $password): array
{ {
return 'token'; return ['status' => 'success', 'data' => ['authToken' => 'token']];
} }
}; };
$apiClient = new class extends ElixFormsApiClient { $apiClient = new class extends ElixFormsApiClient {
@@ -32,14 +32,18 @@ final class ElixFormsControllerTest extends TestCase
string $moduleTag, string $moduleTag,
string $authToken, string $authToken,
string $username, string $username,
?int $status = null ?string $requestStatuses = null
): array ): array
{ {
return [ if ($requestStatuses !== 'IN_PROGRESS,PROCESSED') {
throw new \RuntimeException('requestStatuses non inoltrato al client.');
}
return ['status' => 'success', 'data' => [
['idDomanda' => 10], ['idDomanda' => 10],
['requestId' => 20], ['requestId' => 20],
['idRequest' => 30], ['idRequest' => 30],
]; ]];
} }
public function getExportTags( public function getExportTags(
@@ -69,7 +73,7 @@ final class ElixFormsControllerTest extends TestCase
], ],
]; ];
return [$tags[$requestId]]; return ['status' => 'success', 'data' => [$tags[$requestId]]];
} }
}; };
$config = new class extends Config { $config = new class extends Config {
@@ -85,6 +89,7 @@ final class ElixFormsControllerTest extends TestCase
'moduleTag' => 'MODULO', 'moduleTag' => 'MODULO',
'fieldName' => 'contratto.id', 'fieldName' => 'contratto.id',
'fieldValue' => 'abc-123', 'fieldValue' => 'abc-123',
'requestStatuses' => 'IN_PROGRESS,PROCESSED',
'exportGroup' => ' CUSTOM ', 'exportGroup' => ' CUSTOM ',
]; ];
} }
@@ -97,7 +102,10 @@ final class ElixFormsControllerTest extends TestCase
self::fail('La risposta avrebbe dovuto interrompere il flusso del test.'); self::fail('La risposta avrebbe dovuto interrompere il flusso del test.');
} catch (CapturedResponseException $exception) { } catch (CapturedResponseException $exception) {
self::assertSame(200, $exception->status); self::assertSame(200, $exception->status);
self::assertSame([['requestId' => 20]], $exception->payload); self::assertSame([
'status' => 'success',
'data' => [['requestId' => 20]],
], $exception->payload);
} }
} }