Skip to content

Commit

Permalink
Create a static cache class to share cache pools between tests (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
NanoSector authored Apr 9, 2024
1 parent 2688316 commit dd4843b
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 32 deletions.
20 changes: 20 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,26 @@ composer require --dev gertjuhh/symfony-openapi-validator
- The `operationAddress` can be passed as a third argument for this function but by default it will retrieve the
operation from the `client`.

### Setting up a cache

The [underlying library can use a PSR-6 cache](https://github.com/thephpleague/openapi-psr7-validator#caching-layer--psr-6-support).
This provides a significant speedup when running multiple tests against a single schema, since it can be parsed once and
reused.

In order to activate this cache, you can pass a PSR-6 cache instance to the static property
`\Gertjuhh\SymfonyOpenapiValidator\StaticOpenApiValidatorCache::$validatorCache`. For example:

```php
<?php

use Gertjuhh\SymfonyOpenapiValidator\StaticOpenApiValidatorCache;
use Symfony\Component\Cache\Adapter\ArrayAdapter;

StaticOpenApiValidatorCache::$validatorCache = new ArrayAdapter();
```

This snippet can be embedded in a bootstrap script for PHPUnit.

## Example

```PHP
Expand Down
36 changes: 4 additions & 32 deletions src/OpenApiValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,18 @@

use League\OpenAPIValidation\PSR7\Exception\ValidationFailed;
use League\OpenAPIValidation\PSR7\OperationAddress;
use League\OpenAPIValidation\PSR7\ValidatorBuilder;
use League\OpenAPIValidation\Schema\Exception\NotEnoughValidSchemas;
use League\OpenAPIValidation\Schema\Exception\SchemaMismatch;
use Nyholm\Psr7\Factory\Psr17Factory;
use PHPUnit\Framework\AssertionFailedError;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;

trait OpenApiValidator
{
private static PsrHttpFactory | null $psrHttpFactory = null;

/** @var array<string, ValidatorBuilder> */
private static array $validatorBuilder = [];

/** @throws AssertionFailedError */
public static function assertOpenApiSchema(string $schema, KernelBrowser $client): void
{
$builder = self::getValidatorBuilder($schema);
$psrFactory = self::getPsrHttpFactory();
$builder = StaticOpenApiValidatorCache::getValidatorBuilder($schema);
$psrFactory = StaticOpenApiValidatorCache::getPsrHttpFactory();

try {
$match = $builder->getServerRequestValidator()
Expand All @@ -42,8 +34,8 @@ public static function assertResponseAgainstOpenApiSchema(
KernelBrowser $client,
OperationAddress | null $operationAddress = null,
): void {
$builder = self::getValidatorBuilder($schema);
$psrFactory = self::getPsrHttpFactory();
$builder = StaticOpenApiValidatorCache::getValidatorBuilder($schema);
$psrFactory = StaticOpenApiValidatorCache::getPsrHttpFactory();

if ($operationAddress === null) {
$operationAddress = new OperationAddress(
Expand Down Expand Up @@ -74,25 +66,6 @@ private static function extractPathFromException(\Throwable $exception): string
return null;
}

private static function getPsrHttpFactory(): PsrHttpFactory
{
if (null === self::$psrHttpFactory) {
$psr17Factory = new Psr17Factory();
self::$psrHttpFactory = new PsrHttpFactory($psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory);
}

return self::$psrHttpFactory;
}

private static function getValidatorBuilder(string $schema): ValidatorBuilder
{
if (!\array_key_exists($schema, self::$validatorBuilder)) {
self::$validatorBuilder[$schema] = (new ValidatorBuilder())->fromYamlFile($schema);
}

return self::$validatorBuilder[$schema];
}

private static function wrapValidationException(\Throwable $exception, string $scope): AssertionFailedError
{
$message = [$exception->getMessage()];
Expand Down Expand Up @@ -132,4 +105,3 @@ private static function wrapValidationException(\Throwable $exception, string $s
);
}
}

49 changes: 49 additions & 0 deletions src/StaticOpenApiValidatorCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Gertjuhh\SymfonyOpenapiValidator;

use League\OpenAPIValidation\PSR7\ValidatorBuilder;
use Nyholm\Psr7\Factory\Psr17Factory;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;

final class StaticOpenApiValidatorCache
{
private static PsrHttpFactory | null $psrHttpFactory = null;

/** @var array<string, ValidatorBuilder> */
private static array $validatorBuilder = [];

/**
* Install a cache pool for the OpenAPI Validator
*
* @see https://github.com/thephpleague/openapi-psr7-validator#caching-layer--psr-6-support
*/
public static CacheItemPoolInterface|null $validatorCache = null;

public static function getPsrHttpFactory(): PsrHttpFactory
{
if (null === self::$psrHttpFactory) {
$psr17Factory = new Psr17Factory();
self::$psrHttpFactory = new PsrHttpFactory($psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory);
}

return self::$psrHttpFactory;
}

public static function getValidatorBuilder(string $schema): ValidatorBuilder
{
if (!\array_key_exists($schema, self::$validatorBuilder)) {
self::$validatorBuilder[$schema] = (new ValidatorBuilder())
->fromYamlFile($schema);

if (self::$validatorCache !== null) {
self::$validatorBuilder[$schema]->setCache(self::$validatorCache);
}
}

return self::$validatorBuilder[$schema];
}
}

0 comments on commit dd4843b

Please sign in to comment.