Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

D8AGE-487 Remove the DI container and fix test coverage. #22

Merged
merged 22 commits into from
Jun 11, 2024
Merged

Conversation

intelektron
Copy link
Member

No description provided.

@intelektron intelektron changed the title [DRAFT] D8AGE-487 Remove the DI container. D8AGE-487 Remove the DI container and fix test coverage. Jun 4, 2024
*/
class ApiClient implements ApiClientInterface
{
use ConfigurationAwareTrait;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved all the configuration/token stuff to the factory so I wouldn't have to pass it back and forth.

$httpClient,
$requestFactory,
$streamFactory
);
), $configuration);
}

public function requestToken(): Token
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The interface of this file is not changed.

}

public function setToken(Token $token): self
public function setToken(Token $token): ApiClient
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may seem a little controversial as it breaks the clean architecture, but on the other hand - it keeps things really simple. The token is passed to the factory class.

/**
* @return array<string, string>
*/
public function getAuthorizationHeadersFromToken(Token $token): array;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was a difficult decision, but I finally moved this code here. Previously it was part of the TokenAwareTrait.

*
* Serves as the base for endpoint classes with token support.
*/
abstract class AuthorizedEndpointBase extends EndpointBase
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After removing the container, I noticed that the TokenAwareTrait does not make the code any simpler. On the contrary, it requires a lot of extra lines. I changed it to a shorter solution.

use OpenEuropa\Tests\CdtClient\Traits\ClientTestTrait;
use OpenEuropa\CdtClient\Model\Response\Translation;
use OpenEuropa\Tests\CdtClient\Traits\ApiTestTrait;
use OpenEuropa\Tests\CdtClient\Traits\RequestModelTestTrait;
use PHPUnit\Framework\TestCase;

/**
* @coversDefaultClass \OpenEuropa\CdtClient\ApiClient
*/
class ApiClientTest extends TestCase
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the Achilles heel of the previous version. I've changed it to cover all methods with simple tests. The asserts are not sophisticated, but sufficient to detect any runtime errors.


protected function setUp(): void
/**
* @covers \OpenEuropa\CdtClient\ApiClient
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed to cover the constructor code too,

new Response(200, [], (string) file_get_contents(__DIR__ . '/../fixtures/json/simple_token_call_response.json')),
];
$client = $this->getTestingApiClient([], $responses, false);
self::assertInstanceOf(Token::class, $client->requestToken());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assertions do not care whether the expected results are identical, this type of checking is covered by endpoint testing.

* @covers \OpenEuropa\CdtClient\Http\Rest
*/
public function testIdentifier(string $correlationId, array $clientConfig, array $responses, mixed $expectedResult): void
{
$token = (new Token())->setAccessToken('JWT_TOKEN')
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a microservice-centric approach here. Instead of creating the client and modifying its reflection to access the endpoints illegally, I've just called the constructor of the endpoint. This is shorter and clearer, and makes the test more isolated.

The missing lines are now replaced by ApiClientTest and ApiFactoryTest.

*
* Provides helper methods for testing classes that utilize ApiClient and Rest.
*/
trait ApiTestTrait
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of this code was part of the ClientTestTrait which has been removed. This trait helps us keep the endpoint tests clean.

src/ApiFactory.php Outdated Show resolved Hide resolved
src/Endpoint/AuthorizedEndpointBase.php Outdated Show resolved Hide resolved
{
}

public function downloadFile(string $uri): string
{
try {
$response = $this->rest->get($uri, $this->getAuthorizationHeaders());
$response = $this->rest->get($uri, $this->rest->getAuthorizationHeadersFromToken($this->token));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

y, I think the trait made sense from this point of view


public function createEndpoint(string $class): EndpointBase
{
if ($class === TokenEndpoint::class) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added this one to avoid any confusion in the future. Otherwise, PHP will throw an error about invalid configuration, which is misleading.

*/
public function getAuthorizationHeaders(?Token $token): array
{
if (null === $token) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if is required by PHPStan. I had a lot of trouble re-implementing this method. In the end, I had to allow nullable tokens in the Download class and create additional tests for this exception.

@intelektron
Copy link
Member Author

I fixed the remaining stuff and added a new test for the Rest class. It turned out that 8/12 test paths of the `doRequest' method were not covered.

After my changes there are 4 uncovered paths left. Unfortunately there seems to be a problem with XDebug, explained here. We should test each foreach with three types of arrays: iterable, empty and not iterable (like null). However, we can only pass iterable and empty to the doRequest method. So the path coverage is incomplete, but there's probably no point in fixing it to skew the test results.

src/ApiClient.php Outdated Show resolved Hide resolved
@intelektron intelektron merged commit 127b98f into 1.x Jun 11, 2024
12 checks passed
@intelektron intelektron deleted the D8AGE-487 branch June 11, 2024 13:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants