Skip to content

Commit

Permalink
test(kobo): Mock StoreProxy and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ragusa87 committed Nov 29, 2024
1 parent 26357da commit ec94d72
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 7 deletions.
28 changes: 23 additions & 5 deletions src/Kobo/Proxy/KoboStoreProxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use App\Security\KoboTokenExtractor;
use GuzzleHttp\Client;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Promise\PromiseInterface;
use Nyholm\Psr7\Factory\Psr17Factory;
Expand Down Expand Up @@ -31,6 +32,7 @@ public function __construct(
protected KoboProxyConfiguration $configuration,
protected LoggerInterface $koboProxyLogger,
protected KoboTokenExtractor $tokenExtractor,
protected ?ClientInterface $client = null,
) {
}

Expand Down Expand Up @@ -93,12 +95,10 @@ private function _proxy(Request $request, string $hostname, array $config = []):
$config = $this->getConfig($config);
$psrRequest = $this->convertRequest($request, $hostname);

$accessToken = $this->tokenExtractor->extractAccessToken($request) ?? 'unknown';
$client = $this->getClient($request);

$client = new Client();
$psrResponse = $client->send($psrRequest, [
'base_uri' => $hostname,
'handler' => $this->koboProxyLoggerFactory->createStack($accessToken),
'http_errors' => false,
'connect_timeout' => 5,
] + $config
Expand Down Expand Up @@ -141,7 +141,7 @@ public function proxyAsync(Request $request, bool $streamAllowed): PromiseInterf

$accessToken = $this->tokenExtractor->extractAccessToken($request) ?? 'unknown';

$client = new Client();
$client = $this->getClient($request);

return $client->sendAsync($psrRequest, [
'base_uri' => $upstreamUrl,
Expand Down Expand Up @@ -189,12 +189,30 @@ private function getUpstreamUrl(Request $request): string

private function getConfig(array $config): array
{
// By default, we do not follow redirects, except if explicitly asked otherwise
// By default, we do not follow redirects, except if explicitly$handler asked otherwise
$config['redirect.disable'] ??= true;

// By default, we do stream, except if explicitly asked otherwise
$config['stream'] ??= true;

return $config;
}

public function setClient(?ClientInterface $client): void
{
$this->client = $client;
}

private function getClient(Request $request): ClientInterface
{
if ($this->client instanceof ClientInterface) {
return $this->client;
}

$accessToken = $this->tokenExtractor->extractAccessToken($request) ?? 'unknown';

return new Client([
'handler' => $this->koboProxyLoggerFactory->createStack($accessToken),
]);
}
}
11 changes: 10 additions & 1 deletion src/Kobo/UpstreamSyncMerger.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use App\Entity\KoboDevice;
use App\Kobo\Proxy\KoboStoreProxy;
use App\Kobo\Response\SyncResponse;
use GuzzleHttp\Exception\GuzzleException;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
Expand All @@ -28,7 +29,15 @@ public function merge(KoboDevice $device, SyncResponse $syncResponse, Request $r
return false;
}

$response = $this->koboStoreProxy->proxy($request, ['stream' => false]);
try {
$response = $this->koboStoreProxy->proxy($request, ['stream' => false]);
} catch (GuzzleException $e) {
$this->koboSyncLogger->error('Unable to sync with upstream: {exception}', [
'exception' => $e,
]);

return false;
}
if (false === $response->isOk()) {
$this->koboSyncLogger->error('Sync response is not ok. Got '.$response->getStatusCode());

Expand Down
15 changes: 14 additions & 1 deletion tests/Contraints/JSONIsValidSyncResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,15 @@ public function __construct(protected array $expectedKeysCount)
}
}

const KNOWN_TYPES = ["NewEntitlement", "ChangedTag", "NewTag", "RemovedPublication", "ChangedEntitlement"];
const KNOWN_TYPES = [
"ChangedEntitlement",
"ChangedReadingState",
"ChangedTag",
"DeletedTag",
"NewEntitlement",
"NewTag",
"RemovedPublication",
];
public function matches($other): bool{
try{
$this->test($other);
Expand Down Expand Up @@ -49,6 +57,8 @@ private function test(mixed $other): void
"NewEntitlement" => $this->assertNewEntitlement($item['NewEntitlement']),
"ChangedTag" => $this->assertChangedTag(),
"NewTag" => $this->assertNewTag(),
"DeletedTag" => $this->assertDeletedTag(),
"ChangedReadingState" => null,
"RemovedPublication" => $this->assertRemovedPublication(),
"ChangedEntitlement" => $this->assertChangedEntitlement($item['ChangedEntitlement']),
default => throw new \InvalidArgumentException('Unknown type')
Expand All @@ -71,6 +81,9 @@ private function assertChangedTag(): void
private function assertNewTag(): void
{
}
private function assertDeletedTag(): void
{
}

private function assertRemovedPublication(): void
{
Expand Down
28 changes: 28 additions & 0 deletions tests/Controller/Kobo/AbstractKoboControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@
namespace App\Tests\Controller\Kobo;

use App\Kobo\Kepubify\KepubifyEnabler;
use App\Kobo\Proxy\KoboProxyConfiguration;
use App\Kobo\Proxy\KoboStoreProxy;
use App\Tests\InjectFakeFileSystemTrait;
use GuzzleHttp\Client;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use Symfony\Component\BrowserKit\AbstractBrowser;
use App\DataFixtures\BookFixture;
use App\Entity\Book;
Expand Down Expand Up @@ -90,5 +96,27 @@ protected function getKepubifyEnabler(): KepubifyEnabler

return $service;
}
protected function getKoboStoreProxy(): KoboStoreProxy
{
$service = self::getContainer()->get(KoboStoreProxy::class);
assert($service instanceof KoboStoreProxy);

return $service;
}
protected function getKoboProxyConfiguration(): KoboProxyConfiguration
{
$service = self::getContainer()->get(KoboProxyConfiguration::class);
assert($service instanceof KoboProxyConfiguration);

return $service;
}
protected function getMockClient(string $returnValue): ClientInterface
{
$mock = new MockHandler([
new \GuzzleHttp\Psr7\Response(200, ['Content-Type' => 'application/json'], $returnValue),
]);

$handlerStack = HandlerStack::create($mock);
return new Client(['handler' => $handlerStack]);
}
}
48 changes: 48 additions & 0 deletions tests/Controller/Kobo/KoboSyncControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@

class KoboSyncControllerTest extends AbstractKoboControllerTest
{
protected function tearDown(): void
{
$this->getKoboStoreProxy()->setClient(null);
$this->getKoboProxyConfiguration()->setEnabled(false);
$this->getEntityManager()->getRepository(KoboSyncedBook::class)->deleteAllSyncedBooks(1);

parent::tearDown();
}
public function assertPreConditions(): void
{
$count = $this->getEntityManager()->getRepository(KoboSyncedBook::class)->count(['koboDevice' => 1]);
Expand All @@ -24,6 +31,8 @@ public function testSyncControllerWithForce() : void
$client = static::getClient();
$this->injectFakeFileSystemManager();

$this->getEntityManager()->getRepository(KoboSyncedBook::class)->deleteAllSyncedBooks(1);

$client?->request('GET', '/kobo/'.$this->accessKey.'/v1/library/sync?force=1');

$this->getEntityManager()->getRepository(KoboSyncedBook::class)->deleteAllSyncedBooks(1);
Expand Down Expand Up @@ -61,6 +70,43 @@ public function testSyncControllerWithoutForce() : void

}

public function testSyncControllerWithRemote() : void
{
$client = static::getClient();

// Enable remote sync
$this->getKoboDevice()->setUpstreamSync(true);
$this->getKoboProxyConfiguration()->setEnabled(true);
$this->getEntityManager()->flush();
$this->getKoboDevice(true);

$this->getKoboStoreProxy()->setClient($this->getMockClient('[{
"DeletedTag": {
"Tag": {
"Id": "28521096-ed64-4709-a043-781a0ed0695f",
"LastModified": "2024-02-02T13:35:31.0000000Z"
}
}
}]'));

$this->injectFakeFileSystemManager();

$client?->request('GET', '/kobo/'.$this->accessKey.'/v1/library/sync');

$response = self::getJsonResponse();
self::assertResponseIsSuccessful();
self::assertThat($response, new JSONIsValidSyncResponse([
'NewEntitlement' => 1,
'NewTag' => 1,
'DeletedTag' => 1
]), 'Response is not a valid sync response');


$this->getEntityManager()->getRepository(KoboSyncedBook::class)->deleteAllSyncedBooks(1);
$this->getKoboDevice()->setUpstreamSync(false);
$this->getEntityManager()->flush();
}

public function testSyncControllerMetadata() : void
{
$uuid = $this->getBook()->getUuid();
Expand Down Expand Up @@ -92,4 +138,6 @@ public function testSyncControllerMetadataWithConversion() : void

$this->getEntityManager()->getRepository(KoboSyncedBook::class)->deleteAllSyncedBooks(1);
}


}

0 comments on commit ec94d72

Please sign in to comment.