Migrated GeolocationDbUpdaterTest to use PHPUnit mocks

This commit is contained in:
Alejandro Celaya
2022-10-22 14:27:07 +02:00
parent 4b3ed2b7ba
commit a484455b0b

View File

@@ -7,10 +7,8 @@ namespace ShlinkioTest\Shlink\CLI\GeoLite;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use GeoIp2\Database\Reader; use GeoIp2\Database\Reader;
use MaxMind\Db\Reader\Metadata; use MaxMind\Db\Reader\Metadata;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\CLI\Exception\GeolocationDbUpdateFailedException; use Shlinkio\Shlink\CLI\Exception\GeolocationDbUpdateFailedException;
use Shlinkio\Shlink\CLI\GeoLite\GeolocationDbUpdater; use Shlinkio\Shlink\CLI\GeoLite\GeolocationDbUpdater;
use Shlinkio\Shlink\CLI\GeoLite\GeolocationResult; use Shlinkio\Shlink\CLI\GeoLite\GeolocationResult;
@@ -25,23 +23,18 @@ use function range;
class GeolocationDbUpdaterTest extends TestCase class GeolocationDbUpdaterTest extends TestCase
{ {
use ProphecyTrait; private MockObject $dbUpdater;
private MockObject $geoLiteDbReader;
private GeolocationDbUpdater $geolocationDbUpdater; private MockObject $lock;
private ObjectProphecy $dbUpdater;
private ObjectProphecy $geoLiteDbReader;
private ObjectProphecy $lock;
protected function setUp(): void protected function setUp(): void
{ {
$this->dbUpdater = $this->prophesize(DbUpdaterInterface::class); $this->dbUpdater = $this->createMock(DbUpdaterInterface::class);
$this->geoLiteDbReader = $this->prophesize(Reader::class); $this->geoLiteDbReader = $this->createMock(Reader::class);
$this->trackingOptions = new TrackingOptions(); $this->trackingOptions = new TrackingOptions();
$this->lock = $this->prophesize(Lock\LockInterface::class); $this->lock = $this->createMock(Lock\LockInterface::class);
$this->lock->acquire(true)->willReturn(true); $this->lock->method('acquire')->with($this->isTrue())->willReturn(true);
$this->lock->release()->will(function (): void {
});
} }
/** @test */ /** @test */
@@ -50,25 +43,21 @@ class GeolocationDbUpdaterTest extends TestCase
$mustBeUpdated = fn () => self::assertTrue(true); $mustBeUpdated = fn () => self::assertTrue(true);
$prev = new DbUpdateException(''); $prev = new DbUpdateException('');
$fileExists = $this->dbUpdater->databaseFileExists()->willReturn(false); $this->dbUpdater->expects($this->once())->method('databaseFileExists')->willReturn(false);
$getMeta = $this->geoLiteDbReader->metadata(); $this->dbUpdater->expects($this->once())->method('downloadFreshCopy')->with(
$download = $this->dbUpdater->downloadFreshCopy(null)->willThrow($prev); $this->isNull(),
)->willThrowException($prev);
$this->geoLiteDbReader->expects($this->never())->method('metadata');
try { try {
$this->geolocationDbUpdater()->checkDbUpdate($mustBeUpdated); $this->geolocationDbUpdater()->checkDbUpdate($mustBeUpdated);
self::assertTrue(false); // If this is reached, the test will fail self::fail();
} catch (Throwable $e) { } catch (Throwable $e) {
/** @var GeolocationDbUpdateFailedException $e */ /** @var GeolocationDbUpdateFailedException $e */
self::assertInstanceOf(GeolocationDbUpdateFailedException::class, $e); self::assertInstanceOf(GeolocationDbUpdateFailedException::class, $e);
self::assertSame($prev, $e->getPrevious()); self::assertSame($prev, $e->getPrevious());
self::assertFalse($e->olderDbExists()); self::assertFalse($e->olderDbExists());
} }
$fileExists->shouldHaveBeenCalledOnce();
$getMeta->shouldNotHaveBeenCalled();
$download->shouldHaveBeenCalledOnce();
$this->lock->acquire(true)->shouldHaveBeenCalledOnce();
$this->lock->release()->shouldHaveBeenCalledOnce();
} }
/** /**
@@ -77,26 +66,24 @@ class GeolocationDbUpdaterTest extends TestCase
*/ */
public function exceptionIsThrownWhenOlderDbIsTooOldAndDownloadFails(int $days): void public function exceptionIsThrownWhenOlderDbIsTooOldAndDownloadFails(int $days): void
{ {
$fileExists = $this->dbUpdater->databaseFileExists()->willReturn(true);
$getMeta = $this->geoLiteDbReader->metadata()->willReturn($this->buildMetaWithBuildEpoch(
Chronos::now()->subDays($days)->getTimestamp(),
));
$prev = new DbUpdateException(''); $prev = new DbUpdateException('');
$download = $this->dbUpdater->downloadFreshCopy(null)->willThrow($prev); $this->dbUpdater->expects($this->once())->method('databaseFileExists')->willReturn(true);
$this->dbUpdater->expects($this->once())->method('downloadFreshCopy')->with(
$this->isNull(),
)->willThrowException($prev);
$this->geoLiteDbReader->expects($this->once())->method('metadata')->with()->willReturn(
$this->buildMetaWithBuildEpoch(Chronos::now()->subDays($days)->getTimestamp()),
);
try { try {
$this->geolocationDbUpdater()->checkDbUpdate(); $this->geolocationDbUpdater()->checkDbUpdate();
self::assertTrue(false); // If this is reached, the test will fail self::fail();
} catch (Throwable $e) { } catch (Throwable $e) {
/** @var GeolocationDbUpdateFailedException $e */ /** @var GeolocationDbUpdateFailedException $e */
self::assertInstanceOf(GeolocationDbUpdateFailedException::class, $e); self::assertInstanceOf(GeolocationDbUpdateFailedException::class, $e);
self::assertSame($prev, $e->getPrevious()); self::assertSame($prev, $e->getPrevious());
self::assertTrue($e->olderDbExists()); self::assertTrue($e->olderDbExists());
} }
$fileExists->shouldHaveBeenCalledOnce();
$getMeta->shouldHaveBeenCalledOnce();
$download->shouldHaveBeenCalledOnce();
} }
public function provideBigDays(): iterable public function provideBigDays(): iterable
@@ -113,17 +100,15 @@ class GeolocationDbUpdaterTest extends TestCase
*/ */
public function databaseIsNotUpdatedIfItIsNewEnough(string|int $buildEpoch): void public function databaseIsNotUpdatedIfItIsNewEnough(string|int $buildEpoch): void
{ {
$fileExists = $this->dbUpdater->databaseFileExists()->willReturn(true); $this->dbUpdater->expects($this->once())->method('databaseFileExists')->willReturn(true);
$getMeta = $this->geoLiteDbReader->metadata()->willReturn($this->buildMetaWithBuildEpoch($buildEpoch)); $this->dbUpdater->expects($this->never())->method('downloadFreshCopy');
$download = $this->dbUpdater->downloadFreshCopy(null)->will(function (): void { $this->geoLiteDbReader->expects($this->once())->method('metadata')->with()->willReturn(
}); $this->buildMetaWithBuildEpoch($buildEpoch),
);
$result = $this->geolocationDbUpdater()->checkDbUpdate(); $result = $this->geolocationDbUpdater()->checkDbUpdate();
self::assertEquals(GeolocationResult::DB_IS_UP_TO_DATE, $result); self::assertEquals(GeolocationResult::DB_IS_UP_TO_DATE, $result);
$fileExists->shouldHaveBeenCalledOnce();
$getMeta->shouldHaveBeenCalledOnce();
$download->shouldNotHaveBeenCalled();
} }
public function provideSmallDays(): iterable public function provideSmallDays(): iterable
@@ -139,18 +124,16 @@ class GeolocationDbUpdaterTest extends TestCase
/** @test */ /** @test */
public function exceptionIsThrownWhenCheckingExistingDatabaseWithInvalidBuildEpoch(): void public function exceptionIsThrownWhenCheckingExistingDatabaseWithInvalidBuildEpoch(): void
{ {
$fileExists = $this->dbUpdater->databaseFileExists()->willReturn(true); $this->dbUpdater->expects($this->once())->method('databaseFileExists')->willReturn(true);
$getMeta = $this->geoLiteDbReader->metadata()->willReturn($this->buildMetaWithBuildEpoch('invalid')); $this->dbUpdater->expects($this->never())->method('downloadFreshCopy');
$download = $this->dbUpdater->downloadFreshCopy(null)->will(function (): void { $this->geoLiteDbReader->expects($this->once())->method('metadata')->with()->willReturn(
}); $this->buildMetaWithBuildEpoch('invalid'),
);
$this->expectException(GeolocationDbUpdateFailedException::class); $this->expectException(GeolocationDbUpdateFailedException::class);
$this->expectExceptionMessage( $this->expectExceptionMessage(
'Build epoch with value "invalid" from existing geolocation database, could not be parsed to integer.', 'Build epoch with value "invalid" from existing geolocation database, could not be parsed to integer.',
); );
$fileExists->shouldBeCalledOnce();
$getMeta->shouldBeCalledOnce();
$download->shouldNotBeCalled();
$this->geolocationDbUpdater()->checkDbUpdate(); $this->geolocationDbUpdater()->checkDbUpdate();
} }
@@ -177,10 +160,10 @@ class GeolocationDbUpdaterTest extends TestCase
public function downloadDbIsSkippedIfTrackingIsDisabled(TrackingOptions $options): void public function downloadDbIsSkippedIfTrackingIsDisabled(TrackingOptions $options): void
{ {
$result = $this->geolocationDbUpdater($options)->checkDbUpdate(); $result = $this->geolocationDbUpdater($options)->checkDbUpdate();
$this->dbUpdater->expects($this->never())->method('databaseFileExists');
$this->geoLiteDbReader->expects($this->never())->method('metadata');
self::assertEquals(GeolocationResult::CHECK_SKIPPED, $result); self::assertEquals(GeolocationResult::CHECK_SKIPPED, $result);
$this->dbUpdater->databaseFileExists(Argument::cetera())->shouldNotHaveBeenCalled();
$this->geoLiteDbReader->metadata(Argument::cetera())->shouldNotHaveBeenCalled();
} }
public function provideTrackingOptions(): iterable public function provideTrackingOptions(): iterable
@@ -192,13 +175,13 @@ class GeolocationDbUpdaterTest extends TestCase
private function geolocationDbUpdater(?TrackingOptions $options = null): GeolocationDbUpdater private function geolocationDbUpdater(?TrackingOptions $options = null): GeolocationDbUpdater
{ {
$locker = $this->prophesize(Lock\LockFactory::class); $locker = $this->createMock(Lock\LockFactory::class);
$locker->createLock(Argument::type('string'))->willReturn($this->lock->reveal()); $locker->method('createLock')->with($this->isType('string'))->willReturn($this->lock);
return new GeolocationDbUpdater( return new GeolocationDbUpdater(
$this->dbUpdater->reveal(), $this->dbUpdater,
$this->geoLiteDbReader->reveal(), $this->geoLiteDbReader,
$locker->reveal(), $locker,
$options ?? new TrackingOptions(), $options ?? new TrackingOptions(),
); );
} }