add migrations

Cette révision appartient à :
Daniel Seifert 2023-02-10 00:52:44 +01:00
Parent 028fc05d54
révision 462bb34447
Signé par: DanielS
ID de la clé GPG: 6A513E13AEE66170
13 fichiers modifiés avec 472 ajouts et 226 suppressions

Voir le fichier

@ -63,12 +63,14 @@ and its requirements.
The Flow and Wave themes are supported by default. Other themes may require customisation.
## Module installation
## Module installation / update
Open a command line interface and navigate to the shop root directory (parent of source and vendor). Execute the following command. Adapt the paths to your environment.
Open a command line interface and navigate to the shop root directory (parent of source and vendor). Execute the following commands. Adapt the paths to your environment.
```bash
php composer require d3/oxid-twofactor-passwordless:^1.0
composer require d3/oxid-twofactor-passwordless:^1.0
./vendor/bin/oe-eshop-db_migrate migrations:migrate d3webauthn
```
If a reference to an unsuitable package `symfony/process` is shown, this must be changed. To do this, please add the switch `-W` to the above command (`... require -W ...`).

Voir le fichier

@ -63,12 +63,14 @@ und dessen Anforderungen.
Im Standard wird das Flow- und Wave-Theme unterstützt. Andere Themes können Anpassungen erfordern.
## Modulinstallation
## Modulinstallation / -update
Öffnen Sie eine Kommandozeile und navigieren Sie zum Stammverzeichnis des Shops (Elternverzeichnis von source und vendor). Führen Sie den folgenden Befehl aus. Passen Sie die Pfadangaben an Ihre Installationsumgebung an.
Öffnen Sie eine Kommandozeile und navigieren Sie zum Stammverzeichnis des Shops (Elternverzeichnis von source und vendor). Führen Sie die folgenden Befehle aus. Passen Sie die Pfadangaben an Ihre Installationsumgebung an.
```bash
php composer require d3/oxid-twofactor-passwordless:^1.0
composer require d3/oxid-twofactor-passwordless:^1.0
./vendor/bin/oe-eshop-db_migrate migrations:migrate d3webauthn
```
Wird ein Hinweis auf ein unpassendes Paket "symfony/process" gezeigt, muss dieses geändert werden. Fügen Sie dazu in den oben genannten Befehl bitte den Schalter `-W` ein (`... require -W ...`).

Voir le fichier

@ -55,7 +55,8 @@
},
"autoload": {
"psr-4": {
"D3\\Webauthn\\": "../../../source/modules/d3/oxwebauthn"
"D3\\Webauthn\\": "../../../source/modules/d3/oxwebauthn",
"D3\\Webauthn\\Migrations\\": "../../../source/modules/d3/oxwebauthn/migration/data"
}
},
"suggest": {

Voir le fichier

@ -19,7 +19,7 @@ use Assert\Assert;
use Assert\AssertionFailedException;
use Assert\InvalidArgumentException;
use D3\TestingTools\Production\IsMockable;
use D3\Webauthn\Setup\Actions;
use D3\Webauthn\Migrations\Version20230209212939;
use DateTime;
use Doctrine\DBAL\Driver\Exception as DoctrineDriverException;
use Doctrine\DBAL\Exception as DoctrineException;
@ -76,7 +76,7 @@ class PublicKeyCredential extends BaseModel
Assert::that($encodedCID)
->maxLength(
Actions::FIELDLENGTH_CREDID,
Version20230209212939::FIELDLENGTH_CREDID,
'the credentialId (%3$d) does not fit into the database field (%2$d)'
);
@ -126,7 +126,7 @@ class PublicKeyCredential extends BaseModel
Assert::that($encodedCredential)
->maxLength(
Actions::FIELDLENGTH_CREDENTIAL,
Version20230209212939::FIELDLENGTH_CREDENTIAL,
'the credential source (%3$d) does not fit into the database field (%2$d)',
);

Voir le fichier

@ -110,10 +110,10 @@ class WebauthnLogin
{
/** @var UtilsView $myUtilsView */
$myUtilsView = d3GetOxidDIC()->get('d3ox.webauthn.'.UtilsView::class);
/** @var d3_User_Webauthn $user */
$user = d3GetOxidDIC()->get('d3ox.webauthn.'.User::class);
try {
/** @var d3_User_Webauthn $user */
$user = d3GetOxidDIC()->get('d3ox.webauthn.'.User::class);
$userId = $this->getUserId();
$this->handleErrorMessage();
@ -158,10 +158,10 @@ class WebauthnLogin
{
/** @var UtilsView $myUtilsView */
$myUtilsView = d3GetOxidDIC()->get('d3ox.webauthn.'.UtilsView::class);
/** @var d3_User_Webauthn $user */
$user = d3GetOxidDIC()->get('d3ox.webauthn.'.User::class);
try {
/** @var d3_User_Webauthn $user */
$user = d3GetOxidDIC()->get('d3ox.webauthn.'.User::class);
$userId = $this->getUserId();
$this->handleErrorMessage();
@ -195,8 +195,6 @@ class WebauthnLogin
$user->logout();
$oStr = Str::getStr();
d3GetOxidDIC()->get('d3ox.webauthn.'.Config::class)->getActiveView()
->addTplParam('user', $oStr->htmlspecialchars($userId));
d3GetOxidDIC()->get('d3ox.webauthn.'.Config::class)->getActiveView()
->addTplParam('profile', $oStr->htmlspecialchars($selectedProfile));

Voir le fichier

@ -135,4 +135,11 @@ services:
- 'getDb'
arguments:
- 2
shared: true
shared: true
d3ox.webauthn.OxidEsales\DoctrineMigrationWrapper\MigrationsBuilder:
class: 'OxidEsales\DoctrineMigrationWrapper\MigrationsBuilder'
factory: 'oxNew'
arguments:
- 'OxidEsales\DoctrineMigrationWrapper\MigrationsBuilder'
shared: false

Voir le fichier

@ -18,12 +18,10 @@ namespace D3\Webauthn\Setup;
use D3\TestingTools\Production\IsMockable;
use Doctrine\DBAL\Driver\Exception as DoctrineDriverException;
use Exception;
use OxidEsales\DoctrineMigrationWrapper\MigrationsBuilder;
use OxidEsales\Eshop\Application\Controller\FrontendController;
use OxidEsales\Eshop\Core\Config;
use OxidEsales\Eshop\Core\Database\Adapter\DatabaseInterface;
use OxidEsales\Eshop\Core\DbMetaDataHandler;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
use OxidEsales\Eshop\Core\SeoEncoder;
use OxidEsales\Eshop\Core\Utils;
use OxidEsales\Eshop\Core\UtilsView;
@ -39,93 +37,17 @@ use Psr\Log\LoggerInterface;
class Actions
{
use IsMockable;
public const FIELDLENGTH_CREDID = 512;
public const FIELDLENGTH_CREDENTIAL = 2000;
public $seo_de = 'sicherheitsschluessel';
public $seo_en = 'en/key-authentication';
public $stdClassName = 'd3_account_webauthn';
/**
* SQL statement, that will be executed only at the first time of module installation.
*
* @var string
*/
protected $createCredentialSql =
"CREATE TABLE `d3wa_usercredentials` (
`OXID` char(32) NOT NULL,
`OXUSERID` char(32) NOT NULL,
`OXSHOPID` int(11) NOT NULL,
`NAME` varchar(100) NOT NULL,
`CREDENTIALID` varchar(".self::FIELDLENGTH_CREDID.") NOT NULL,
`CREDENTIAL` varchar(".self::FIELDLENGTH_CREDENTIAL.") NOT NULL,
`OXTIMESTAMP` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
PRIMARY KEY (`OXID`),
KEY `CREDENTIALID_IDX` (`CREDENTIALID`),
KEY `SHOPUSER_IDX` (`OXUSERID`,`OXSHOPID`) USING BTREE
) ENGINE=InnoDB COMMENT='WebAuthn Credentials';";
/**
* Execute the sql at the first time of the module installation.
* @return void
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
public function setupModule()
public function runModuleMigrations()
{
if (!$this->tableExists('d3wa_usercredentials')) {
$this->executeSQL($this->createCredentialSql);
}
}
/**
* Check if table exists
*
* @param string $sTableName table name
*
* @return bool
*/
public function tableExists(string $sTableName): bool
{
$oDbMetaDataHandler = d3GetOxidDIC()->get('d3ox.webauthn.'.DbMetaDataHandler::class);
return $oDbMetaDataHandler->tableExists($sTableName);
}
/**
* @return DatabaseInterface|null
* @throws DatabaseConnectionException
*/
protected function d3GetDb(): ?DatabaseInterface
{
/** @var DatabaseInterface $db */
$db = d3GetOxidDIC()->get('d3ox.webauthn.'.DatabaseInterface::class.'.assoc');
return $db;
}
/**
* Executes given sql statement.
*
* @param string $sSQL Sql to execute.
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
public function executeSQL(string $sSQL)
{
$this->d3GetDb()->execute($sSQL);
}
/**
* Check if field exists in table
*
* @param string $sFieldName field name
* @param string $sTableName table name
*
* @return bool
*/
public function fieldExists(string $sFieldName, string $sTableName): bool
{
$oDbMetaDataHandler = d3GetOxidDIC()->get('d3ox.webauthn.'.DbMetaDataHandler::class);
return $oDbMetaDataHandler->fieldExists($sFieldName, $sTableName);
/** @var MigrationsBuilder $migrationsBuilder */
$migrationsBuilder = d3GetOxidDIC()->get('d3ox.webauthn.'.MigrationsBuilder::class);
$migrations = $migrationsBuilder->build();
$migrations->execute('migrations:migrate', 'd3webauthn');
}
/**

Voir le fichier

@ -34,7 +34,7 @@ class Events
}
$actions = oxNew(Actions::class);
$actions->setupModule();
$actions->runModuleMigrations();
$actions->regenerateViews();
$actions->clearCache();
$actions->seoUrl();

Voir le fichier

@ -0,0 +1,112 @@
<?php
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1);
namespace D3\Webauthn\Migrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Types\DateTimeType;
use Doctrine\DBAL\Types\IntegerType;
use Doctrine\DBAL\Types\StringType;
use Doctrine\Migrations\AbstractMigration;
final class Version20230209212939 extends AbstractMigration
{
public const FIELDLENGTH_CREDID = 512;
public const FIELDLENGTH_CREDENTIAL = 2000;
public function getDescription() : string
{
return 'create credential database table';
}
public function up(Schema $schema) : void
{
$this->connection->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
$table = !$schema->hasTable('d3wa_usercredentials') ?
$schema->createTable('d3wa_usercredentials') :
$schema->getTable('d3wa_usercredentials');
if (!$table->hasColumn('OXID')) {
$table->addColumn('OXID', (new StringType())->getName())
->setLength(32)
->setFixed(true)
->setNotnull(true);
}
if (!$table->hasColumn('OXUSERID')) {
$table->addColumn('OXUSERID', (new StringType())->getName())
->setLength(32)
->setFixed(true)
->setNotnull(true);
}
if (!$table->hasColumn('OXSHOPID')) {
$table->addColumn('OXSHOPID', (new IntegerType())->getName())
->setLength(11)
->setNotnull(true);
}
if (!$table->hasColumn('NAME')) {
$table->addColumn('NAME', (new StringType())->getName())
->setLength(100)
->setFixed(false)
->setNotnull(true);
}
if (!$table->hasColumn('CREDENTIALID')) {
$table->addColumn('CREDENTIALID', (new StringType())->getName())
->setLength(self::FIELDLENGTH_CREDID)
->setFixed(false)
->setNotnull(true);
}
if (!$table->hasColumn('CREDENTIAL')) {
$table->addColumn('CREDENTIAL', (new StringType())->getName())
->setLength(self::FIELDLENGTH_CREDENTIAL)
->setFixed(false)
->setNotnull(true);
}
if (!$table->hasColumn('OXTIMESTAMP')) {
$table->addColumn('OXTIMESTAMP', (new DateTimeType())->getName())
->setType(new DateTimeType())
->setNotnull(true)
// can't set default value via default method
->setColumnDefinition('timestamp DEFAULT CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP');
}
if (!$table->hasPrimaryKey()) {
$table->setPrimaryKey(['OXID']);
}
if (!$table->hasIndex('SHOPUSER_IDX')) {
$table->addIndex(['OXUSERID', 'OXSHOPID'], 'SHOPUSER_IDX');
}
if (!$table->hasIndex('CREDENTIALID_IDX')) {
$table->addIndex(['CREDENTIALID'], 'CREDENTIALID_IDX');
}
$table->setComment('WebAuthn Credentials');
}
public function down(Schema $schema) : void
{
if ($schema->hasTable('d3wa_usercredentials')) {
$schema->dropTable('d3wa_usercredentials');
}
}
}

4
src/migration/migrations.yml Fichier exécutable
Voir le fichier

@ -0,0 +1,4 @@
name: D3 Twofactor Passwordless
migrations_namespace: D3\Webauthn\Migrations
table_name: d3wa_migrations
migrations_directory: data

Voir le fichier

@ -15,6 +15,7 @@
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">../Application</directory>
<directory suffix=".php">../migration</directory>
<directory suffix=".php">../Modules</directory>
<directory suffix=".php">../Setup</directory>
<exclude>

Voir le fichier

@ -19,9 +19,9 @@ use D3\TestingTools\Development\CanAccessRestricted;
use D3\Webauthn\Setup\Actions;
use D3\Webauthn\tests\unit\WAUnitTestCase;
use Exception;
use OxidEsales\DoctrineMigrationWrapper\Migrations;
use OxidEsales\DoctrineMigrationWrapper\MigrationsBuilder;
use OxidEsales\Eshop\Application\Controller\FrontendController;
use OxidEsales\Eshop\Core\Database\Adapter\DatabaseInterface;
use OxidEsales\Eshop\Core\Database\Adapter\Doctrine\Database;
use OxidEsales\Eshop\Core\DbMetaDataHandler;
use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\SeoEncoder;
@ -45,141 +45,35 @@ class ActionsTest extends WAUnitTestCase
/**
* @test
* @param $tableExist
* @param $expectedInvocation
* @return void
* @throws ReflectionException
* @covers \D3\Webauthn\Setup\Actions::setupModule
* @dataProvider canSetupModuleDataProvider
* @covers \D3\Webauthn\Setup\Actions::runModuleMigrations()
*/
public function canSetupModule($tableExist, $expectedInvocation)
public function canRunModuleMigrations()
{
/** @var Actions|MockObject $sut */
$sut = $this->getMockBuilder(Actions::class)
->onlyMethods(['tableExists', 'executeSQL'])
->getMock();
$sut->method('tableExists')->willReturn($tableExist);
$sut->expects($expectedInvocation)->method('executeSQL')->willReturn(true);
$this->callMethod(
$sut,
'setupModule'
);
}
/**
* @return array[]
*/
public function canSetupModuleDataProvider(): array
{
return [
'table exist' => [true, $this->never()],
'table not exist' => [false, $this->once()],
];
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Webauthn\Setup\Actions::tableExists
*/
public function canCheckTableExists()
{
$expected = true;
/** @var DbMetaDataHandler|MockObject $DbMetaDataMock */
$DbMetaDataMock = $this->getMockBuilder(DbMetaDataHandler::class)
->onlyMethods(['tableExists'])
->getMock();
$DbMetaDataMock->expects($this->once())->method('tableExists')->willReturn($expected);
d3GetOxidDIC()->set('d3ox.webauthn.'.DbMetaDataHandler::class, $DbMetaDataMock);
/** @var Actions $sut */
$sut = oxNew(Actions::class);
$this->assertSame(
$expected,
$this->callMethod(
$sut,
'tableExists',
['testTable']
)
);
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Webauthn\Setup\Actions::d3GetDb
*/
public function d3GetDbReturnsRightInstance()
{
$sut = oxNew(Actions::class);
$this->assertInstanceOf(
DatabaseInterface::class,
$this->callMethod(
$sut,
'd3GetDb'
)
);
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Webauthn\Setup\Actions::executeSQL
*/
public function canExecuteSQL()
{
/** @var Database|MockObject $dbMock */
$dbMock = $this->getMockBuilder(Database::class)
/** @var Migrations|MockObject $migrationMock */
$migrationMock = $this->getMockBuilder(Migrations::class)
->onlyMethods(['execute'])
->disableOriginalConstructor()
->getMock();
$dbMock->expects($this->once())->method('execute');
$sut = $this->getMockBuilder(Actions::class)
->onlyMethods(['d3GetDb'])
->getMock();
$sut->method('d3GetDb')->willReturn($dbMock);
$this->callMethod(
$sut,
'executeSQL',
['query']
$migrationMock->expects($this->atLeastOnce())->method('execute')->with(
$this->identicalTo('migrations:migrate'),
$this->identicalTo('d3webauthn')
);
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Webauthn\Setup\Actions::fieldExists
*/
public function canCheckFieldExists()
{
$expected = true;
/** @var DbMetaDataHandler|MockObject $DbMetaDataMock */
$DbMetaDataMock = $this->getMockBuilder(DbMetaDataHandler::class)
->onlyMethods(['fieldExists'])
/** @var MigrationsBuilder|MockObject $migrationsBuilderMock */
$migrationsBuilderMock = $this->getMockBuilder(MigrationsBuilder::class)
->onlyMethods(['build'])
->getMock();
$DbMetaDataMock->expects($this->once())->method('fieldExists')->willReturn($expected);
d3GetOxidDIC()->set('d3ox.webauthn.'.DbMetaDataHandler::class, $DbMetaDataMock);
$migrationsBuilderMock->method('build')->willReturn($migrationMock);
d3GetOxidDIC()->set('d3ox.webauthn.'.MigrationsBuilder::class, $migrationsBuilderMock);
/** @var Actions $sut */
$sut = oxNew(Actions::class);
$this->assertSame(
$expected,
$this->callMethod(
$sut,
'fieldExists',
['testField', 'testTable']
)
$this->callMethod(
$sut,
'runModuleMigrations'
);
}

Voir le fichier

@ -0,0 +1,303 @@
<?php
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1);
namespace D3\Webauthn\tests\unit\migration\data;
use D3\TestingTools\Development\CanAccessRestricted;
use D3\Webauthn\Migrations\Version20230209212939;
use D3\Webauthn\tests\unit\WAUnitTestCase;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\MySQL57Platform;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\MySqlSchemaManager;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\Table;
use Doctrine\Migrations\Configuration\Configuration;
use Doctrine\Migrations\Version\Version;
use Generator;
use PHPUnit\Framework\MockObject\MockObject;
use ReflectionException;
class Version20230209212939Test extends WAUnitTestCase
{
use CanAccessRestricted;
/** @var Version20230209212939 */
protected $sut;
public function setUp(): void
{
parent::setUp(); // TODO: Change the autogenerated stub
/** @var AbstractPlatform|MockObject $databasePlatformMock */
$databasePlatformMock = $this->getMockBuilder(MySQL57Platform::class)
->getMock();
/** @var AbstractSchemaManager|MockObject $schemaManagerMock */
$schemaManagerMock = $this->getMockBuilder(MySqlSchemaManager::class)
->disableOriginalConstructor()
->getMock();
/** @var Connection|MockObject $connectionMock */
$connectionMock = $this->getMockBuilder(Connection::class)
->disableOriginalConstructor()
->onlyMethods(['getDatabasePlatform', 'getSchemaManager'])
->getMock();
$connectionMock->method('getDatabasePlatform')->willReturn($databasePlatformMock);
$connectionMock->method('getSchemaManager')->willReturn($schemaManagerMock);
/** @var Configuration|MockObject $configurationMock */
$configurationMock = $this->getMockBuilder(Configuration::class)
->disableOriginalConstructor()
->onlyMethods(['getConnection'])
->getMock();
$configurationMock->method('getConnection')->willReturn($connectionMock);
/** @var Version|MockObject $versionMock */
$versionMock = $this->getMockBuilder(Version::class)
->onlyMethods(['getConfiguration'])
->disableOriginalConstructor()
->getMock();
$versionMock->method('getConfiguration')->willReturn($configurationMock);
$this->sut = oxNew(Version20230209212939::class, $versionMock);
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Webauthn\Migrations\Version20230209212939::getDescription
*/
public function canGetDescription()
{
$this->assertIsString(
$this->callMethod(
$this->sut,
'getDescription'
)
);
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Webauthn\Migrations\Version20230209212939::up
* @dataProvider canUpTableDataProvider
*/
public function canUpTable($tableExist, $invocationCount)
{
/** @var Table|MockObject $tableMock */
$tableMock = $this->getMockBuilder(Table::class)
->onlyMethods(['hasColumn', 'hasPrimaryKey', 'hasIndex'])
->disableOriginalConstructor()
->getMock();
$tableMock->method('hasColumn')->willReturn(true);
$tableMock->method('hasPrimaryKey')->willReturn(true);
$tableMock->method('hasIndex')->willReturn(true);
/** @var Schema|MockObject $schemaMock */
$schemaMock = $this->getMockBuilder(Schema::class)
->onlyMethods(['hasTable', 'createTable', 'getTable'])
->getMock();
$schemaMock->method('hasTable')->willReturn($tableExist);
$schemaMock->expects($invocationCount)->method('createTable')->willReturn($tableMock);
$schemaMock->method('getTable')->willReturn($tableMock);
$this->callMethod(
$this->sut,
'up',
[$schemaMock]
);
}
/**
* @return Generator
*/
public function canUpTableDataProvider(): Generator
{
yield 'table not exist' => [false, $this->once()];
yield 'table exist' => [true, $this->never()];
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Webauthn\Migrations\Version20230209212939::up
* @dataProvider canUpColumnDataProvider
*/
public function canUpColumn($columnExist, $invocationCount)
{
/** @var Column|MockObject $columnMock */
$columnMock = $this->getMockBuilder(Column::class)
->onlyMethods(['setLength'])
->disableOriginalConstructor()
->getMock();
$columnMock->method('setLength')->willReturnSelf();
/** @var Table|MockObject $tableMock */
$tableMock = $this->getMockBuilder(Table::class)
->onlyMethods(['hasColumn', 'addColumn', 'hasPrimaryKey', 'hasIndex'])
->disableOriginalConstructor()
->getMock();
$tableMock->method('hasColumn')->willReturn($columnExist);
$tableMock->expects($invocationCount)->method('addColumn')->willReturn($columnMock);
$tableMock->method('hasPrimaryKey')->willReturn(true);
$tableMock->method('hasIndex')->willReturn(true);
/** @var Schema|MockObject $schemaMock */
$schemaMock = $this->getMockBuilder(Schema::class)
->onlyMethods(['hasTable', 'getTable'])
->getMock();
$schemaMock->method('hasTable')->willReturn(true);
$schemaMock->method('getTable')->willReturn($tableMock);
$this->callMethod(
$this->sut,
'up',
[$schemaMock]
);
}
/**
* @return Generator
*/
public function canUpColumnDataProvider(): Generator
{
yield 'column not exist' => [false, $this->atLeast(7)];
yield 'column exist' => [true, $this->never()];
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Webauthn\Migrations\Version20230209212939::up
* @dataProvider canUpPrimaryKeyDataProvider
*/
public function canUpPrimaryKey($pKeyExist, $invocationCount)
{
/** @var Table|MockObject $tableMock */
$tableMock = $this->getMockBuilder(Table::class)
->onlyMethods(['hasColumn', 'addColumn', 'hasPrimaryKey', 'hasIndex', 'setPrimaryKey'])
->disableOriginalConstructor()
->getMock();
$tableMock->method('hasColumn')->willReturn(true);
$tableMock->method('hasPrimaryKey')->willReturn($pKeyExist);
$tableMock->method('hasIndex')->willReturn(true);
$tableMock->expects($invocationCount)->method('setPrimaryKey');
/** @var Schema|MockObject $schemaMock */
$schemaMock = $this->getMockBuilder(Schema::class)
->onlyMethods(['hasTable', 'getTable'])
->getMock();
$schemaMock->method('hasTable')->willReturn(true);
$schemaMock->method('getTable')->willReturn($tableMock);
$this->callMethod(
$this->sut,
'up',
[$schemaMock]
);
}
/**
* @return Generator
*/
public function canUpPrimaryKeyDataProvider(): Generator
{
yield 'pk not exist' => [false, $this->once()];
yield 'pk exist' => [true, $this->never()];
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Webauthn\Migrations\Version20230209212939::up
* @dataProvider canUpIndexDataProvider
*/
public function canUpIndex($indexExist, $invocationCount)
{
/** @var Table|MockObject $tableMock */
$tableMock = $this->getMockBuilder(Table::class)
->onlyMethods(['hasColumn', 'addColumn', 'hasPrimaryKey', 'hasIndex', 'addIndex', 'setComment'])
->disableOriginalConstructor()
->getMock();
$tableMock->method('hasColumn')->willReturn(true);
$tableMock->method('hasPrimaryKey')->willReturn(true);
$tableMock->method('hasIndex')->willReturn($indexExist);
$tableMock->expects($invocationCount)->method('addIndex');
$tableMock->expects($this->once())->method('setComment');
/** @var Schema|MockObject $schemaMock */
$schemaMock = $this->getMockBuilder(Schema::class)
->onlyMethods(['hasTable', 'getTable'])
->getMock();
$schemaMock->method('hasTable')->willReturn(true);
$schemaMock->method('getTable')->willReturn($tableMock);
$this->callMethod(
$this->sut,
'up',
[$schemaMock]
);
}
/**
* @return Generator
*/
public function canUpIndexDataProvider(): Generator
{
yield 'index not exist' => [false, $this->atLeast(2)];
yield 'index exist' => [true, $this->never()];
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Webauthn\Migrations\Version20230209212939::down
* @dataProvider canDownTableDataProvider
*/
public function canDownTable($tableExist, $invocationCount)
{
/** @var Schema|MockObject $schemaMock */
$schemaMock = $this->getMockBuilder(Schema::class)
->onlyMethods(['hasTable', 'dropTable'])
->getMock();
$schemaMock->method('hasTable')->willReturn($tableExist);
$schemaMock->expects($invocationCount)->method('dropTable');
$this->callMethod(
$this->sut,
'down',
[$schemaMock]
);
}
/**
* @return Generator
*/
public function canDownTableDataProvider(): Generator
{
yield 'table exist' => [true, $this->once()];
yield 'table not exist' => [false, $this->never()];
}
}