Added event dispatching to UpdateGeoLiteDb dispatcher so that it locates visits when file has just been created

This commit is contained in:
Alejandro Celaya 2022-09-18 11:17:17 +02:00
parent eab9347522
commit ef01754ad5
6 changed files with 70 additions and 7 deletions

View File

@ -2,6 +2,7 @@
Here listed you will find the different architectural decisions taken in the project, including all the reasoning behind it, options considered, and final outcome. Here listed you will find the different architectural decisions taken in the project, including all the reasoning behind it, options considered, and final outcome.
* [2022-09-18 Allow delaying initial GeoLite2 DB download in docker images](2022-09-18-allow-delaying-initial-geolite2-db-download-in-docker-images.md)
* [2022-08-05 Support multi-segment custom slugs](2022-08-05-support-multi-segment-custom-slugs.md) * [2022-08-05 Support multi-segment custom slugs](2022-08-05-support-multi-segment-custom-slugs.md)
* [2022-01-15 Update env vars behavior to have precedence over installer options](2022-01-15-update-env-vars-behavior-to-have-precedence-over-installer-options.md) * [2022-01-15 Update env vars behavior to have precedence over installer options](2022-01-15-update-env-vars-behavior-to-have-precedence-over-installer-options.md)
* [2021-08-05 Migrate to a new caching library](2021-08-05-migrate-to-a-new-caching-library.md) * [2021-08-05 Migrate to a new caching library](2021-08-05-migrate-to-a-new-caching-library.md)

View File

@ -20,6 +20,9 @@ return [
EventDispatcher\Event\UrlVisited::class => [ EventDispatcher\Event\UrlVisited::class => [
EventDispatcher\LocateVisit::class, EventDispatcher\LocateVisit::class,
], ],
EventDispatcher\Event\GeoLiteDbCreated::class => [
// EventDispatcher\LocateUnloctedVisits::class,
],
], ],
'async' => [ 'async' => [
EventDispatcher\Event\VisitLocated::class => [ EventDispatcher\Event\VisitLocated::class => [
@ -132,7 +135,11 @@ return [
'Logger_Shlink', 'Logger_Shlink',
'config.redis.pub_sub_enabled', 'config.redis.pub_sub_enabled',
], ],
EventDispatcher\UpdateGeoLiteDb::class => [GeolocationDbUpdater::class, 'Logger_Shlink'], EventDispatcher\UpdateGeoLiteDb::class => [
GeolocationDbUpdater::class,
'Logger_Shlink',
EventDispatcherInterface::class,
],
], ],
]; ];

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Core\EventDispatcher\Event;
final class GeoLiteDbCreated
{
}

View File

@ -4,16 +4,22 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\EventDispatcher; namespace Shlinkio\Shlink\Core\EventDispatcher;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Shlinkio\Shlink\CLI\GeoLite\GeolocationDbUpdaterInterface; use Shlinkio\Shlink\CLI\GeoLite\GeolocationDbUpdaterInterface;
use Shlinkio\Shlink\CLI\GeoLite\GeolocationResult;
use Shlinkio\Shlink\Core\EventDispatcher\Event\GeoLiteDbCreated;
use Throwable; use Throwable;
use function sprintf; use function sprintf;
class UpdateGeoLiteDb class UpdateGeoLiteDb
{ {
public function __construct(private GeolocationDbUpdaterInterface $dbUpdater, private LoggerInterface $logger) public function __construct(
{ private readonly GeolocationDbUpdaterInterface $dbUpdater,
private readonly LoggerInterface $logger,
private readonly EventDispatcherInterface $eventDispatcher,
) {
} }
public function __invoke(): void public function __invoke(): void
@ -32,7 +38,10 @@ class UpdateGeoLiteDb
}; };
try { try {
$this->dbUpdater->checkDbUpdate($beforeDownload, $handleProgress); $result = $this->dbUpdater->checkDbUpdate($beforeDownload, $handleProgress);
if ($result === GeolocationResult::DB_CREATED) {
$this->eventDispatcher->dispatch(new GeoLiteDbCreated());
}
} catch (Throwable $e) { } catch (Throwable $e) {
$this->logger->error('GeoLite2 database download failed. {e}', ['e' => $e]); $this->logger->error('GeoLite2 database download failed. {e}', ['e' => $e]);
} }

View File

@ -8,12 +8,16 @@ use PHPUnit\Framework\TestCase;
use Prophecy\Argument; use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy; use Prophecy\Prophecy\ObjectProphecy;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use RuntimeException; use RuntimeException;
use Shlinkio\Shlink\CLI\GeoLite\GeolocationDbUpdaterInterface; use Shlinkio\Shlink\CLI\GeoLite\GeolocationDbUpdaterInterface;
use Shlinkio\Shlink\CLI\GeoLite\GeolocationResult; use Shlinkio\Shlink\CLI\GeoLite\GeolocationResult;
use Shlinkio\Shlink\Core\EventDispatcher\Event\GeoLiteDbCreated;
use Shlinkio\Shlink\Core\EventDispatcher\UpdateGeoLiteDb; use Shlinkio\Shlink\Core\EventDispatcher\UpdateGeoLiteDb;
use function Functional\map;
class UpdateGeoLiteDbTest extends TestCase class UpdateGeoLiteDbTest extends TestCase
{ {
use ProphecyTrait; use ProphecyTrait;
@ -21,13 +25,19 @@ class UpdateGeoLiteDbTest extends TestCase
private UpdateGeoLiteDb $listener; private UpdateGeoLiteDb $listener;
private ObjectProphecy $dbUpdater; private ObjectProphecy $dbUpdater;
private ObjectProphecy $logger; private ObjectProphecy $logger;
private ObjectProphecy $eventDispatcher;
protected function setUp(): void protected function setUp(): void
{ {
$this->dbUpdater = $this->prophesize(GeolocationDbUpdaterInterface::class); $this->dbUpdater = $this->prophesize(GeolocationDbUpdaterInterface::class);
$this->logger = $this->prophesize(LoggerInterface::class); $this->logger = $this->prophesize(LoggerInterface::class);
$this->eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
$this->listener = new UpdateGeoLiteDb($this->dbUpdater->reveal(), $this->logger->reveal()); $this->listener = new UpdateGeoLiteDb(
$this->dbUpdater->reveal(),
$this->logger->reveal(),
$this->eventDispatcher->reveal(),
);
} }
/** @test */ /** @test */
@ -43,6 +53,7 @@ class UpdateGeoLiteDbTest extends TestCase
$checkDbUpdate->shouldHaveBeenCalledOnce(); $checkDbUpdate->shouldHaveBeenCalledOnce();
$logError->shouldHaveBeenCalledOnce(); $logError->shouldHaveBeenCalledOnce();
$this->logger->notice(Argument::cetera())->shouldNotHaveBeenCalled(); $this->logger->notice(Argument::cetera())->shouldNotHaveBeenCalled();
$this->eventDispatcher->dispatch(Argument::cetera())->shouldNotHaveBeenCalled();
} }
/** /**
@ -56,7 +67,7 @@ class UpdateGeoLiteDbTest extends TestCase
[$firstCallback] = $args; [$firstCallback] = $args;
$firstCallback($oldDbExists); $firstCallback($oldDbExists);
return GeolocationResult::DB_CREATED; return GeolocationResult::DB_IS_UP_TO_DATE;
}, },
); );
$logNotice = $this->logger->notice($expectedMessage); $logNotice = $this->logger->notice($expectedMessage);
@ -66,6 +77,7 @@ class UpdateGeoLiteDbTest extends TestCase
$checkDbUpdate->shouldHaveBeenCalledOnce(); $checkDbUpdate->shouldHaveBeenCalledOnce();
$logNotice->shouldHaveBeenCalledOnce(); $logNotice->shouldHaveBeenCalledOnce();
$this->logger->error(Argument::cetera())->shouldNotHaveBeenCalled(); $this->logger->error(Argument::cetera())->shouldNotHaveBeenCalled();
$this->eventDispatcher->dispatch(Argument::cetera())->shouldNotHaveBeenCalled();
} }
public function provideFlags(): iterable public function provideFlags(): iterable
@ -93,7 +105,7 @@ class UpdateGeoLiteDbTest extends TestCase
$secondCallback($total, $downloaded, $oldDbExists); $secondCallback($total, $downloaded, $oldDbExists);
$secondCallback($total, $downloaded, $oldDbExists); $secondCallback($total, $downloaded, $oldDbExists);
return GeolocationResult::DB_CREATED; return GeolocationResult::DB_UPDATED;
}, },
); );
$logNotice = $this->logger->notice($expectedMessage ?? Argument::cetera()); $logNotice = $this->logger->notice($expectedMessage ?? Argument::cetera());
@ -107,6 +119,7 @@ class UpdateGeoLiteDbTest extends TestCase
} }
$checkDbUpdate->shouldHaveBeenCalledOnce(); $checkDbUpdate->shouldHaveBeenCalledOnce();
$this->logger->error(Argument::cetera())->shouldNotHaveBeenCalled(); $this->logger->error(Argument::cetera())->shouldNotHaveBeenCalled();
$this->eventDispatcher->dispatch(Argument::cetera())->shouldNotHaveBeenCalled();
} }
public function provideDownloaded(): iterable public function provideDownloaded(): iterable
@ -120,4 +133,28 @@ class UpdateGeoLiteDbTest extends TestCase
yield [100, 101, true, 'Finished updating GeoLite2 db file']; yield [100, 101, true, 'Finished updating GeoLite2 db file'];
yield [100, 101, false, 'Finished downloading GeoLite2 db file']; yield [100, 101, false, 'Finished downloading GeoLite2 db file'];
} }
/**
* @test
* @dataProvider provideGeolocationResults
*/
public function dispatchesEventOnlyWhenDbFileHasBeenCreatedForTheFirstTime(
GeolocationResult $result,
int $expectedDispatches,
): void {
$checkDbUpdate = $this->dbUpdater->checkDbUpdate(Argument::cetera())->willReturn($result);
($this->listener)();
$checkDbUpdate->shouldHaveBeenCalledOnce();
$this->eventDispatcher->dispatch(new GeoLiteDbCreated())->shouldHaveBeenCalledTimes($expectedDispatches);
}
public function provideGeolocationResults(): iterable
{
return map(GeolocationResult::cases(), static fn (GeolocationResult $value) => [
$value,
$value === GeolocationResult::DB_CREATED ? 1 : 0,
]);
}
} }