From 308b36f05cb6ecf646114023eb3ec42f70423be5 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sat, 3 Jun 2023 14:11:04 +0200 Subject: [PATCH 01/52] moved method --- src/TestSuite/TestCase.php | 16 ++++++++++++++++ tests/TestCase/Driver/DriverTest.php | 15 --------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/TestSuite/TestCase.php b/src/TestSuite/TestCase.php index f725489c..d97bdfff 100644 --- a/src/TestSuite/TestCase.php +++ b/src/TestSuite/TestCase.php @@ -16,6 +16,7 @@ namespace DatabaseBackup\TestSuite; use DatabaseBackup\BackupTrait; +use DatabaseBackup\Driver\Driver; use DatabaseBackup\Utility\BackupManager; use MeTools\TestSuite\TestCase as BaseTestCase; @@ -36,4 +37,19 @@ public function tearDown(): void parent::tearDown(); } + + /** + * Internal method to get a mock for `Driver` abstract class + * @param array $mockedMethods Mocked methods + * @return \DatabaseBackup\Driver\Driver&\PHPUnit\Framework\MockObject\MockObject + */ + protected function getMockForAbstractDriver(array $mockedMethods = []): Driver + { + /** @var \Cake\Database\Connection $Connection */ + $Connection = $this->getConnection('test'); + /** @var \DatabaseBackup\Driver\Driver&\PHPUnit\Framework\MockObject\MockObject $Driver */ + $Driver = $this->createPartialMockForAbstractClass(Driver::class, $mockedMethods, [$Connection]); + + return $Driver; + } } diff --git a/tests/TestCase/Driver/DriverTest.php b/tests/TestCase/Driver/DriverTest.php index a08033f5..1183eb3a 100644 --- a/tests/TestCase/Driver/DriverTest.php +++ b/tests/TestCase/Driver/DriverTest.php @@ -34,21 +34,6 @@ class DriverTest extends TestCase */ protected Driver $Driver; - /** - * Internal method to get a mock for `Driver` abstract class - * @param array $mockedMethods Mocked methods - * @return \DatabaseBackup\Driver\Driver&\PHPUnit\Framework\MockObject\MockObject - */ - protected function getMockForAbstractDriver(array $mockedMethods = []): Driver - { - /** @var \Cake\Database\Connection $Connection */ - $Connection = $this->getConnection('test'); - /** @var \DatabaseBackup\Driver\Driver&\PHPUnit\Framework\MockObject\MockObject $Driver */ - $Driver = $this->createPartialMockForAbstractClass(Driver::class, $mockedMethods, [$Connection]); - - return $Driver; - } - /** * Internal method to get a mock for `Driver` abstract class, with the `_exec()` method that returns a `Process` * instance with a failure and a custom error message From 5fb386be5970347fceae16a49669586b5e87f654 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sat, 3 Jun 2023 14:54:08 +0200 Subject: [PATCH 02/52] the events (`Backup.beforeExport`, `Backup.afterExport`, `Backup.beforeImport`, `Backup.afterImport`, which remain implemented by the driver classes) are directly dispatched by the `BackupExport::export()` and `BackupImport::import()` methods, and no longer by the drivers themselves --- CHANGELOG.md | 8 ++++++ src/Driver/Driver.php | 28 +++------------------ src/TestSuite/DriverTestCase.php | 12 ++++++--- src/Utility/BackupExport.php | 22 +++++++++++++--- src/Utility/BackupImport.php | 24 +++++++++++++++--- tests/TestCase/Driver/DriverTest.php | 24 ------------------ tests/TestCase/Utility/BackupExportTest.php | 17 +++++++++++++ tests/TestCase/Utility/BackupImportTest.php | 18 +++++++++++++ version | 2 +- 9 files changed, 94 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62a4ca5b..2dcb551f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,12 @@ # 2.x branch +## 2.12 branch +### 2.12.0 +* the events (`Backup.beforeExport`, `Backup.afterExport`, `Backup.beforeImport`, `Backup.afterImport`, which remain + implemented by the driver classes) are directly dispatched by the `BackupExport::export()` and `BackupImport::import()` + methods, and no longer by the drivers themselves; +* the `BackupExport::export()` and `BackupImport::import()` methods can return the filename path on success or `false` + if the `Backup.beforeExport`/`Backup.beforeImport` events are stopped. + ## 2.11 branch ### 2.11.1 * added the `DatabaseBackup.processTimeout` configuration, which allows you to set a timeout for commands that will be diff --git a/src/Driver/Driver.php b/src/Driver/Driver.php index f7deb071..e485d5a6 100644 --- a/src/Driver/Driver.php +++ b/src/Driver/Driver.php @@ -211,54 +211,32 @@ final public function getConfig(?string $key = null) } /** - * Exports the database. - * - * When exporting, this method will trigger these events: - * - `Backup.beforeExport`: will be triggered before export; - * - `Backup.afterExport`: will be triggered after export. + * Exports the database * @param string $filename Filename where you want to export the database * @return bool `true` on success * @throws \Exception */ final public function export(string $filename): bool { - $beforeExport = $this->dispatchEvent('Backup.beforeExport'); - if ($beforeExport->isStopped()) { - return false; - } - $process = $this->_exec($this->_getExportExecutable($filename)); Exceptionist::isTrue($process->isSuccessful(), __d('database_backup', 'Export failed with error message: `{0}`', rtrim($process->getErrorOutput()))); - $this->dispatchEvent('Backup.afterExport'); - return file_exists($filename); } /** - * Imports the database. - * - * When importing, this method will trigger these events: - * - `Backup.beforeImport`: will be triggered before import; - * - `Backup.afterImport`: will be triggered after import. + * Imports the database * @param string $filename Filename from which you want to import the database - * @return bool true on success + * @return bool `true` on success * @throws \Tools\Exception\NotInArrayException * @throws \ReflectionException * @throws \ErrorException */ final public function import(string $filename): bool { - $beforeImport = $this->dispatchEvent('Backup.beforeImport'); - if ($beforeImport->isStopped()) { - return false; - } - $process = $this->_exec($this->_getImportExecutable($filename)); Exceptionist::isTrue($process->isSuccessful(), __d('database_backup', 'Import failed with error message: `{0}`', rtrim($process->getErrorOutput()))); - $this->dispatchEvent('Backup.afterImport'); - return true; } } diff --git a/src/TestSuite/DriverTestCase.php b/src/TestSuite/DriverTestCase.php index a357f028..e22d7f9c 100644 --- a/src/TestSuite/DriverTestCase.php +++ b/src/TestSuite/DriverTestCase.php @@ -110,10 +110,9 @@ public function testExport(): void { $backup = $this->getAbsolutePath('example.sql'); $this->assertFileDoesNotExist($backup); + $this->Driver->dispatchEvent('Backup.beforeExport'); $this->assertTrue($this->Driver->export($backup)); $this->assertFileExists($backup); - $this->assertEventFired('Backup.beforeExport', $this->Driver->getEventManager()); - $this->assertEventFired('Backup.afterExport', $this->Driver->getEventManager()); } /** @@ -135,7 +134,9 @@ public function testExportAndImport(): void $this->assertCount(6, $initial['Comments']); //Exports backup and deletes article with ID 2 and comment with ID 4 + $this->Driver->dispatchEvent('Backup.beforeExport'); $this->assertTrue($this->Driver->export($backup)); + $this->Driver->dispatchEvent('Backup.afterExport'); $this->Articles->delete($this->Articles->get(2), ['atomic' => false]); $this->Comments->delete($this->Comments->get(4), ['atomic' => false]); @@ -145,7 +146,9 @@ public function testExportAndImport(): void $this->assertCount(count($initial['Comments']) - 1, $afterDelete['Comments']); //Imports backup. Now initial records are the same of final records + $this->Driver->dispatchEvent('Backup.beforeImport'); $this->assertTrue($this->Driver->import($backup)); + $this->Driver->dispatchEvent('Backup.afterImport'); $final = $this->getAllRecords(); $this->assertEquals($initial, $final); @@ -194,10 +197,11 @@ public function testGetExportExecutable(): void public function testImport(): void { $backup = $this->getAbsolutePath('example.sql'); + $this->Driver->dispatchEvent('Backup.beforeExport'); $this->assertTrue($this->Driver->export($backup)); + $this->Driver->dispatchEvent('Backup.afterExport'); + $this->Driver->dispatchEvent('Backup.beforeImport'); $this->assertTrue($this->Driver->import($backup)); - $this->assertEventFired('Backup.beforeImport', $this->Driver->getEventManager()); - $this->assertEventFired('Backup.afterImport', $this->Driver->getEventManager()); } /** diff --git a/src/Utility/BackupExport.php b/src/Utility/BackupExport.php index e04ba6fa..e6d6d5bb 100644 --- a/src/Utility/BackupExport.php +++ b/src/Utility/BackupExport.php @@ -181,12 +181,18 @@ public function send(?string $recipient = null) } /** - * Exports the database - * @return string Filename path + * Exports the database. + * + * When exporting, this method will trigger these events (implemented by the driver instance): + * - `Backup.beforeExport`: will be triggered before export; + * - `Backup.afterExport`: will be triggered after export. + * @return string|false Filename path on success or `false` if the `Backup.beforeExport` event is stopped * @throws \Exception + * @see \DatabaseBackup\Driver\Driver::afterExport() + * @see \DatabaseBackup\Driver\Driver::beforeExport() * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-the-BackupExport-utility#export */ - public function export(): string + public function export() { if (empty($this->filename)) { $this->extension ??= $this->defaultExtension; @@ -197,9 +203,19 @@ public function export(): string $filename = $this->filename; unset($this->filename); + //Dispatches the `Backup.beforeExport` event implemented by the driver + $BeforeExport = $this->Driver->dispatchEvent('Backup.beforeExport'); + if ($BeforeExport->isStopped()) { + return false; + } + + //Exports $this->Driver->export($filename); Filesystem::instance()->chmod($filename, Configure::read('DatabaseBackup.chmod')); + //Dispatches the `Backup.afterExport` event implemented by the driver + $this->Driver->dispatchEvent('Backup.afterExport'); + if ($this->emailRecipient) { $this->BackupManager->send($filename, $this->emailRecipient); } diff --git a/src/Utility/BackupImport.php b/src/Utility/BackupImport.php index 9f37e429..9710639f 100644 --- a/src/Utility/BackupImport.php +++ b/src/Utility/BackupImport.php @@ -30,7 +30,7 @@ class BackupImport * Driver containing all methods to export/import database backups according to the connection * @var \DatabaseBackup\Driver\Driver */ - protected Driver $Driver; + public Driver $Driver; /** * Filename where to import the database @@ -68,12 +68,18 @@ public function filename(string $filename) } /** - * Imports the database - * @return string Filename path + * Imports the database. + * + * When importing, this method will trigger these events (implemented by the driver instance): + * - `Backup.beforeImport`: will be triggered before import; + * - `Backup.afterImport`: will be triggered after import. + * @return string|false Filename path on success or `false` if the `Backup.beforeImport` event is stopped * @throws \ErrorException|\ReflectionException + * @see \DatabaseBackup\Driver\Driver::afterImport() + * @see \DatabaseBackup\Driver\Driver::beforeImport() * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-the-BackupImport-utility#import */ - public function import(): string + public function import() { Exceptionist::isTrue(!empty($this->filename), __d('database_backup', 'You must first set the filename')); @@ -81,8 +87,18 @@ public function import(): string $filename = $this->filename; unset($this->filename); + //Dispatches the `Backup.beforeImport` event implemented by the driver + $BeforeImport = $this->Driver->dispatchEvent('Backup.beforeImport'); + if ($BeforeImport->isStopped()) { + return false; + } + + //Imports $this->Driver->import($filename); + //Dispatches the `Backup.afterImport` event implemented by the driver + $this->Driver->dispatchEvent('Backup.afterImport'); + return $filename; } } diff --git a/tests/TestCase/Driver/DriverTest.php b/tests/TestCase/Driver/DriverTest.php index 1183eb3a..2e4a8f35 100644 --- a/tests/TestCase/Driver/DriverTest.php +++ b/tests/TestCase/Driver/DriverTest.php @@ -114,18 +114,6 @@ public function testExportExceedingTimeout(): void $Driver->export($this->getAbsolutePath('example.sql')); } - /** - * Test for `export()` method. Export is stopped because the `beforeExport()` method returns `false` - * @test - * @uses \DatabaseBackup\Driver\Driver::export() - */ - public function testExportStoppedByBeforeExport(): void - { - $Driver = $this->getMockForAbstractDriver(['beforeExport']); - $Driver->method('beforeExport')->willReturn(false); - $this->assertFalse($Driver->export($this->getAbsolutePath('example.sql'))); - } - /** * Test for `import()` method on failure * @test @@ -155,16 +143,4 @@ public function testImportExceedingTimeout(): void $Driver->method('_exec')->willThrowException($ProcessTimedOutException); $Driver->import($this->getAbsolutePath('example.sql')); } - - /** - * Test for `import()` method. Import is stopped because the `beforeImport()` method returns `false` - * @test - * @uses \DatabaseBackup\Driver\Driver::import() - */ - public function testImportStoppedByBeforeExport(): void - { - $Driver = $this->getMockForAbstractDriver(['beforeImport']); - $Driver->method('beforeImport')->willReturn(false); - $this->assertFalse($Driver->import($this->getAbsolutePath('example.sql'))); - } } diff --git a/tests/TestCase/Utility/BackupExportTest.php b/tests/TestCase/Utility/BackupExportTest.php index a446016a..fb304eb1 100644 --- a/tests/TestCase/Utility/BackupExportTest.php +++ b/tests/TestCase/Utility/BackupExportTest.php @@ -16,6 +16,7 @@ namespace DatabaseBackup\Test\TestCase\Utility; use Cake\Core\Configure; +use Cake\Event\EventList; use Cake\TestSuite\EmailTrait; use DatabaseBackup\TestSuite\TestCase; use DatabaseBackup\Utility\BackupExport; @@ -43,6 +44,7 @@ public function setUp(): void parent::setUp(); $this->BackupExport ??= new BackupExport(); + $this->BackupExport->Driver->getEventManager()->setEventList(new EventList()); } /** @@ -136,6 +138,8 @@ public function testExport(): void $file = $this->BackupExport->export(); $this->assertFileExists($file); $this->assertMatchesRegularExpression('/^backup_test_\d{14}\.sql$/', basename($file)); + $this->assertEventFired('Backup.beforeExport', $this->BackupExport->Driver->getEventManager()); + $this->assertEventFired('Backup.afterExport', $this->BackupExport->Driver->getEventManager()); //Exports with `compression()` $file = $this->BackupExport->compression('bzip2')->export(); @@ -175,4 +179,17 @@ public function testExportWithDifferentChmod(): void $file = $this->BackupExport->filename('exportWithDifferentChmod.sql')->export(); $this->assertSame('0777', substr(sprintf('%o', fileperms($file)), -4)); } + + /** + * Test for `export()` method. Export is stopped by the `Backup.beforeExport` event (implemented by driver) + * @test + * @uses \DatabaseBackup\Utility\BackupExport::export() + */ + public function testExportStoppedByBeforeExport(): void + { + $Driver = $this->getMockForAbstractDriver(['beforeExport']); + $Driver->method('beforeExport')->willReturn(false); + $this->BackupExport->Driver = $Driver; + $this->assertFalse($this->BackupExport->export()); + } } diff --git a/tests/TestCase/Utility/BackupImportTest.php b/tests/TestCase/Utility/BackupImportTest.php index 23841c84..062836fe 100644 --- a/tests/TestCase/Utility/BackupImportTest.php +++ b/tests/TestCase/Utility/BackupImportTest.php @@ -15,6 +15,7 @@ */ namespace DatabaseBackup\Test\TestCase\Utility; +use Cake\Event\EventList; use DatabaseBackup\TestSuite\TestCase; use DatabaseBackup\Utility\BackupExport; use DatabaseBackup\Utility\BackupImport; @@ -49,6 +50,7 @@ public function setUp(): void $this->BackupExport ??= new BackupExport(); $this->BackupImport ??= new BackupImport(); + $this->BackupImport->Driver->getEventManager()->setEventList(new EventList()); } /** @@ -97,6 +99,8 @@ public function testImport(): void $backup = $this->BackupExport->compression(null)->export(); $filename = $this->BackupImport->filename($backup)->import(); $this->assertMatchesRegularExpression('/^backup_test_[0-9]{14}\.sql$/', basename($filename)); + $this->assertEventFired('Backup.beforeImport', $this->BackupImport->Driver->getEventManager()); + $this->assertEventFired('Backup.afterImport', $this->BackupImport->Driver->getEventManager()); //Exports and imports with `bzip2` compression $backup = $this->BackupExport->compression('bzip2')->export(); @@ -111,4 +115,18 @@ public function testImport(): void $this->expectExceptionMessage('You must first set the filename'); $this->BackupImport->import(); } + + /** + * Test for `import()` method. Export is stopped by the `Backup.beforeImport` event (implemented by driver) + * @test + * @uses \DatabaseBackup\Utility\BackupImport::import() + */ + public function testImportStoppedByBeforeExport(): void + { + $Driver = $this->getMockForAbstractDriver(['beforeImport']); + $Driver->method('beforeImport')->willReturn(false); + $this->BackupImport->Driver = $Driver; + $this->BackupImport->filename(createBackup()); + $this->assertFalse($this->BackupImport->import()); + } } diff --git a/version b/version index 6ceb272e..d8b69897 100644 --- a/version +++ b/version @@ -1 +1 @@ -2.11.1 +2.12.0 From f22284a8af80e77e565222b99b33509c3145e350 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sat, 3 Jun 2023 15:13:46 +0200 Subject: [PATCH 03/52] updated tests --- src/Command/ExportCommand.php | 7 ++++++- src/Command/ImportCommand.php | 11 ++++++++++- tests/TestCase/Utility/BackupExportTest.php | 12 ++++++------ tests/TestCase/Utility/BackupImportTest.php | 18 +++++++++--------- tests/TestCase/Utility/BackupManagerTest.php | 4 ++-- tests/bootstrap.php | 2 +- 6 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/Command/ExportCommand.php b/src/Command/ExportCommand.php index 4741d46c..f9ffcfd1 100644 --- a/src/Command/ExportCommand.php +++ b/src/Command/ExportCommand.php @@ -21,6 +21,7 @@ use DatabaseBackup\Console\Command; use DatabaseBackup\Utility\BackupExport; use Exception; +use Tools\Exceptionist; /** * Exports a database backup @@ -85,8 +86,12 @@ public function execute(Arguments $args, ConsoleIo $io): void $BackupExport->compression((string)$args->getOption('compression')); } - //Exports + /** + * Exports + * @var string $file + */ $file = $BackupExport->export(); + Exceptionist::isTrue($file, __d('database_backup', 'The `{0}` event stopped the operation', 'Backup.beforeExport')); $io->success(__d('database_backup', 'Backup `{0}` has been exported', rtr($file))); $verbose = $args->getOption('verbose'); diff --git a/src/Command/ImportCommand.php b/src/Command/ImportCommand.php index 74bdf347..3890da6e 100644 --- a/src/Command/ImportCommand.php +++ b/src/Command/ImportCommand.php @@ -21,6 +21,7 @@ use DatabaseBackup\Console\Command; use DatabaseBackup\Utility\BackupImport; use Exception; +use Tools\Exceptionist; /** * Imports a database backup @@ -54,7 +55,15 @@ public function execute(Arguments $args, ConsoleIo $io): void parent::execute($args, $io); try { - $file = (new BackupImport())->filename((string)$args->getArgument('filename'))->import(); + $BackupImport = new BackupImport(); + $BackupImport->filename((string)$args->getArgument('filename')); + + /** + * Imports + * @var string $file + */ + $file = $BackupImport->import(); + Exceptionist::isTrue($file, __d('database_backup', 'The `{0}` event stopped the operation', 'Backup.beforeImport')); $io->success(__d('database_backup', 'Backup `{0}` has been imported', rtr($file))); } catch (Exception $e) { $io->error($e->getMessage()); diff --git a/tests/TestCase/Utility/BackupExportTest.php b/tests/TestCase/Utility/BackupExportTest.php index fb304eb1..6dbf3d10 100644 --- a/tests/TestCase/Utility/BackupExportTest.php +++ b/tests/TestCase/Utility/BackupExportTest.php @@ -135,25 +135,25 @@ public function testSend(): void */ public function testExport(): void { - $file = $this->BackupExport->export(); + $file = $this->BackupExport->export() ?: ''; $this->assertFileExists($file); $this->assertMatchesRegularExpression('/^backup_test_\d{14}\.sql$/', basename($file)); $this->assertEventFired('Backup.beforeExport', $this->BackupExport->Driver->getEventManager()); $this->assertEventFired('Backup.afterExport', $this->BackupExport->Driver->getEventManager()); //Exports with `compression()` - $file = $this->BackupExport->compression('bzip2')->export(); + $file = $this->BackupExport->compression('bzip2')->export() ?: ''; $this->assertFileExists($file); $this->assertMatchesRegularExpression('/^backup_test_\d{14}\.sql\.bz2$/', basename($file)); //Exports with `filename()` - $file = $this->BackupExport->filename('backup.sql.bz2')->export(); + $file = $this->BackupExport->filename('backup.sql.bz2')->export() ?: ''; $this->assertFileExists($file); $this->assertSame('backup.sql.bz2', basename($file)); //Exports with `send()` $recipient = 'recipient@example.com'; - $file = $this->BackupExport->filename('exportWithSend.sql')->send($recipient)->export(); + $file = $this->BackupExport->filename('exportWithSend.sql')->send($recipient)->export() ?: ''; $this->assertMailSentFrom(Configure::readOrFail('DatabaseBackup.mailSender')); $this->assertMailSentTo($recipient); $this->assertMailSentWith('Database backup ' . basename($file) . ' from localhost', 'subject'); @@ -172,11 +172,11 @@ public function testExport(): void */ public function testExportWithDifferentChmod(): void { - $file = $this->BackupExport->filename('exportWithNormalChmod.sql')->export(); + $file = $this->BackupExport->filename('exportWithNormalChmod.sql')->export() ?: ''; $this->assertSame('0664', substr(sprintf('%o', fileperms($file)), -4)); Configure::write('DatabaseBackup.chmod', 0777); - $file = $this->BackupExport->filename('exportWithDifferentChmod.sql')->export(); + $file = $this->BackupExport->filename('exportWithDifferentChmod.sql')->export() ?: ''; $this->assertSame('0777', substr(sprintf('%o', fileperms($file)), -4)); } diff --git a/tests/TestCase/Utility/BackupImportTest.php b/tests/TestCase/Utility/BackupImportTest.php index 062836fe..23e44262 100644 --- a/tests/TestCase/Utility/BackupImportTest.php +++ b/tests/TestCase/Utility/BackupImportTest.php @@ -61,17 +61,17 @@ public function setUp(): void public function testFilename(): void { //Creates a `sql` backup - $backup = $this->BackupExport->filename('backup.sql')->export(); + $backup = $this->BackupExport->filename('backup.sql')->export() ?: ''; $this->BackupImport->filename($backup); $this->assertSame($backup, $this->getProperty($this->BackupImport, 'filename')); //Creates a `sql.bz2` backup - $backup = $this->BackupExport->filename('backup.sql.bz2')->export(); + $backup = $this->BackupExport->filename('backup.sql.bz2')->export() ?: ''; $this->BackupImport->filename($backup); $this->assertSame($backup, $this->getProperty($this->BackupImport, 'filename')); //Creates a `sql.gz` backup - $backup = $this->BackupExport->filename('backup.sql.gz')->export(); + $backup = $this->BackupExport->filename('backup.sql.gz')->export() ?: ''; $this->BackupImport->filename($backup); $this->assertSame($backup, $this->getProperty($this->BackupImport, 'filename')); @@ -96,20 +96,20 @@ public function testFilename(): void public function testImport(): void { //Exports and imports with no compression - $backup = $this->BackupExport->compression(null)->export(); - $filename = $this->BackupImport->filename($backup)->import(); + $backup = $this->BackupExport->compression(null)->export() ?: ''; + $filename = $this->BackupImport->filename($backup)->import() ?: ''; $this->assertMatchesRegularExpression('/^backup_test_[0-9]{14}\.sql$/', basename($filename)); $this->assertEventFired('Backup.beforeImport', $this->BackupImport->Driver->getEventManager()); $this->assertEventFired('Backup.afterImport', $this->BackupImport->Driver->getEventManager()); //Exports and imports with `bzip2` compression - $backup = $this->BackupExport->compression('bzip2')->export(); - $filename = $this->BackupImport->filename($backup)->import(); + $backup = $this->BackupExport->compression('bzip2')->export() ?: ''; + $filename = $this->BackupImport->filename($backup)->import() ?: ''; $this->assertMatchesRegularExpression('/^backup_test_[0-9]{14}\.sql\.bz2$/', basename($filename)); //Exports and imports with `gzip` compression - $backup = $this->BackupExport->compression('gzip')->export(); - $filename = $this->BackupImport->filename($backup)->import(); + $backup = $this->BackupExport->compression('gzip')->export() ?: ''; + $filename = $this->BackupImport->filename($backup)->import() ?: ''; $this->assertMatchesRegularExpression('/^backup_test_[0-9]{14}\.sql\.gz$/', basename($filename)); $this->expectExceptionMessage('You must first set the filename'); diff --git a/tests/TestCase/Utility/BackupManagerTest.php b/tests/TestCase/Utility/BackupManagerTest.php index f410071f..90f7ffef 100644 --- a/tests/TestCase/Utility/BackupManagerTest.php +++ b/tests/TestCase/Utility/BackupManagerTest.php @@ -62,13 +62,13 @@ public function setUp(): void */ public function testDelete(): void { - $filename = $this->BackupExport->export(); + $filename = $this->BackupExport->export() ?: ''; $this->assertFileExists($filename); $this->assertSame($filename, $this->BackupManager->delete($filename)); $this->assertFileDoesNotExist($filename); //With a relative path - $filename = $this->BackupExport->export(); + $filename = $this->BackupExport->export() ?: ''; $this->assertFileExists($filename); $this->assertSame($filename, $this->BackupManager->delete(basename($filename))); $this->assertFileDoesNotExist($filename); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index dc5ddca9..a6eb5995 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -133,7 +133,7 @@ class_alias('DatabaseBackup\TestSuite\BaseCommandTestCase', 'MeTools\TestSuite\C */ function createBackup(string $filename = 'backup.sql'): string { - return (new BackupExport())->filename($filename)->export(); + return (new BackupExport())->filename($filename)->export() ?: ''; } } From f1e17d726022f655c41bd7239bef7be17fdaf2c0 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sat, 3 Jun 2023 15:24:45 +0200 Subject: [PATCH 04/52] completely improved the `BackupImportTest` tests --- CHANGELOG.md | 3 +- tests/TestCase/Utility/BackupImportTest.php | 55 ++++++--------------- 2 files changed, 18 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dcb551f..cce9e017 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ implemented by the driver classes) are directly dispatched by the `BackupExport::export()` and `BackupImport::import()` methods, and no longer by the drivers themselves; * the `BackupExport::export()` and `BackupImport::import()` methods can return the filename path on success or `false` - if the `Backup.beforeExport`/`Backup.beforeImport` events are stopped. + if the `Backup.beforeExport`/`Backup.beforeImport` events are stopped; +* completely improved the `BackupImportTest` tests. ## 2.11 branch ### 2.11.1 diff --git a/tests/TestCase/Utility/BackupImportTest.php b/tests/TestCase/Utility/BackupImportTest.php index 23e44262..b476641d 100644 --- a/tests/TestCase/Utility/BackupImportTest.php +++ b/tests/TestCase/Utility/BackupImportTest.php @@ -17,7 +17,6 @@ use Cake\Event\EventList; use DatabaseBackup\TestSuite\TestCase; -use DatabaseBackup\Utility\BackupExport; use DatabaseBackup\Utility\BackupImport; use Tools\Exception\NotReadableException; use Tools\Filesystem; @@ -30,11 +29,6 @@ class BackupImportTest extends TestCase { use ReflectionTrait; - /** - * @var \DatabaseBackup\Utility\BackupExport - */ - protected BackupExport $BackupExport; - /** * @var \DatabaseBackup\Utility\BackupImport */ @@ -48,7 +42,6 @@ public function setUp(): void { parent::setUp(); - $this->BackupExport ??= new BackupExport(); $this->BackupImport ??= new BackupImport(); $this->BackupImport->Driver->getEventManager()->setEventList(new EventList()); } @@ -60,24 +53,16 @@ public function setUp(): void */ public function testFilename(): void { - //Creates a `sql` backup - $backup = $this->BackupExport->filename('backup.sql')->export() ?: ''; - $this->BackupImport->filename($backup); - $this->assertSame($backup, $this->getProperty($this->BackupImport, 'filename')); - - //Creates a `sql.bz2` backup - $backup = $this->BackupExport->filename('backup.sql.bz2')->export() ?: ''; - $this->BackupImport->filename($backup); - $this->assertSame($backup, $this->getProperty($this->BackupImport, 'filename')); - - //Creates a `sql.gz` backup - $backup = $this->BackupExport->filename('backup.sql.gz')->export() ?: ''; - $this->BackupImport->filename($backup); - $this->assertSame($backup, $this->getProperty($this->BackupImport, 'filename')); + foreach (array_keys(DATABASE_BACKUP_EXTENSIONS) as $extension) { + $result = createBackup('backup.' . $extension); + $this->BackupImport->filename($result); + $this->assertSame($result, $this->getProperty($this->BackupImport, 'filename')); + } //With a relative path - $this->BackupImport->filename(basename($backup)); - $this->assertSame($backup, $this->getProperty($this->BackupImport, 'filename')); + $result = createBackup('backup_' . time() . '.sql'); + $this->BackupImport->filename(basename($result)); + $this->assertSame($result, $this->getProperty($this->BackupImport, 'filename')); //With an invalid directory $this->expectException(NotReadableException::class); @@ -95,22 +80,14 @@ public function testFilename(): void */ public function testImport(): void { - //Exports and imports with no compression - $backup = $this->BackupExport->compression(null)->export() ?: ''; - $filename = $this->BackupImport->filename($backup)->import() ?: ''; - $this->assertMatchesRegularExpression('/^backup_test_[0-9]{14}\.sql$/', basename($filename)); - $this->assertEventFired('Backup.beforeImport', $this->BackupImport->Driver->getEventManager()); - $this->assertEventFired('Backup.afterImport', $this->BackupImport->Driver->getEventManager()); - - //Exports and imports with `bzip2` compression - $backup = $this->BackupExport->compression('bzip2')->export() ?: ''; - $filename = $this->BackupImport->filename($backup)->import() ?: ''; - $this->assertMatchesRegularExpression('/^backup_test_[0-9]{14}\.sql\.bz2$/', basename($filename)); - - //Exports and imports with `gzip` compression - $backup = $this->BackupExport->compression('gzip')->export() ?: ''; - $filename = $this->BackupImport->filename($backup)->import() ?: ''; - $this->assertMatchesRegularExpression('/^backup_test_[0-9]{14}\.sql\.gz$/', basename($filename)); + foreach (array_keys(DATABASE_BACKUP_EXTENSIONS) as $extension) { + $expectedFilename = createBackup('backup.' . $extension); + $result = $this->BackupImport->filename($expectedFilename)->import() ?: ''; + $this->assertStringEndsWith('backup.' . $extension, $result); + $this->assertSame($expectedFilename, $result); + $this->assertEventFired('Backup.beforeImport', $this->BackupImport->Driver->getEventManager()); + $this->assertEventFired('Backup.afterImport', $this->BackupImport->Driver->getEventManager()); + } $this->expectExceptionMessage('You must first set the filename'); $this->BackupImport->import(); From 73ddd871d70bf8b89ecff9aabc946acf86e2c3db Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sat, 3 Jun 2023 18:16:36 +0200 Subject: [PATCH 05/52] moved method --- src/TestSuite/TestCase.php | 16 ++++++++++++++++ tests/TestCase/Driver/DriverTest.php | 15 --------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/TestSuite/TestCase.php b/src/TestSuite/TestCase.php index d97bdfff..53d52415 100644 --- a/src/TestSuite/TestCase.php +++ b/src/TestSuite/TestCase.php @@ -19,6 +19,7 @@ use DatabaseBackup\Driver\Driver; use DatabaseBackup\Utility\BackupManager; use MeTools\TestSuite\TestCase as BaseTestCase; +use Symfony\Component\Process\Process; /** * TestCase class @@ -52,4 +53,19 @@ protected function getMockForAbstractDriver(array $mockedMethods = []): Driver return $Driver; } + + /** + * Internal method to get a mock for `Driver` abstract class, with the `_exec()` method that returns a `Process` + * instance with a failure and a custom error message + * @param string $errorMessage The error message + * @return \DatabaseBackup\Driver\Driver&\PHPUnit\Framework\MockObject\MockObject + */ + protected function getMockForAbstractDriverWithErrorProcess(string $errorMessage): Driver + { + $Process = $this->createConfiguredMock(Process::class, ['getErrorOutput' => $errorMessage . PHP_EOL, 'isSuccessful' => false]); + $Driver = $this->getMockForAbstractDriver(['_exec']); + $Driver->method('_exec')->willReturn($Process); + + return $Driver; + } } diff --git a/tests/TestCase/Driver/DriverTest.php b/tests/TestCase/Driver/DriverTest.php index 2e4a8f35..1b358684 100644 --- a/tests/TestCase/Driver/DriverTest.php +++ b/tests/TestCase/Driver/DriverTest.php @@ -34,21 +34,6 @@ class DriverTest extends TestCase */ protected Driver $Driver; - /** - * Internal method to get a mock for `Driver` abstract class, with the `_exec()` method that returns a `Process` - * instance with a failure and a custom error message - * @param string $errorMessage The error message - * @return \DatabaseBackup\Driver\Driver&\PHPUnit\Framework\MockObject\MockObject - */ - protected function getMockForAbstractDriverWithErrorProcess(string $errorMessage): Driver - { - $Process = $this->createConfiguredMock(Process::class, ['getErrorOutput' => $errorMessage . PHP_EOL, 'isSuccessful' => false]); - $Driver = $this->getMockForAbstractDriver(['_exec']); - $Driver->method('_exec')->willReturn($Process); - - return $Driver; - } - /** * Called before every test method * @return void From 02ab200dcdebcbeb37d04b21ba6d508545f109cf Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sat, 3 Jun 2023 19:04:35 +0200 Subject: [PATCH 06/52] the code of `Driver::export()` and `Driver::import()` methods has been absorbed by `BackupExport::export()` and `BackupImport::import()` and therefore those methods no longer exist --- CHANGELOG.md | 2 + src/Driver/Driver.php | 36 +---- src/TestSuite/DriverTestCase.php | 141 +------------------- src/Utility/BackupExport.php | 3 +- src/Utility/BackupImport.php | 4 +- tests/TestCase/Driver/DriverTest.php | 62 --------- tests/TestCase/Utility/BackupExportTest.php | 31 +++++ tests/TestCase/Utility/BackupImportTest.php | 33 +++++ 8 files changed, 77 insertions(+), 235 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cce9e017..10567bea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ methods, and no longer by the drivers themselves; * the `BackupExport::export()` and `BackupImport::import()` methods can return the filename path on success or `false` if the `Backup.beforeExport`/`Backup.beforeImport` events are stopped; +* the code of `Driver::export()` and `Driver::import()` methods has been absorbed by `BackupExport::export()` and + `BackupImport::import()` and therefore those methods no longer exist; * completely improved the `BackupImportTest` tests. ## 2.11 branch diff --git a/src/Driver/Driver.php b/src/Driver/Driver.php index e485d5a6..5a31dd3f 100644 --- a/src/Driver/Driver.php +++ b/src/Driver/Driver.php @@ -72,7 +72,7 @@ final public function implementedEvents(): array * @return \Symfony\Component\Process\Process * @since 2.8.7 */ - protected function _exec(string $command): Process + public function _exec(string $command): Process { $Process = Process::fromShellCommandline($command); $Process->setTimeout(Configure::read('DatabaseBackup.processTimeout', 60)); @@ -118,7 +118,7 @@ protected function _getExecutable(string $type): string * @throws \ReflectionException * @throws \ErrorException */ - protected function _getExportExecutable(string $filename): string + public function _getExportExecutable(string $filename): string { $exec = $this->_getExecutable('export'); $compression = self::getCompression($filename); @@ -137,7 +137,7 @@ protected function _getExportExecutable(string $filename): string * @throws \ReflectionException * @throws \ErrorException */ - protected function _getImportExecutable(string $filename): string + public function _getImportExecutable(string $filename): string { $exec = $this->_getExecutable('import'); $compression = self::getCompression($filename); @@ -209,34 +209,4 @@ final public function getConfig(?string $key = null) return $key ? $config[$key] ?? null : $config; } - - /** - * Exports the database - * @param string $filename Filename where you want to export the database - * @return bool `true` on success - * @throws \Exception - */ - final public function export(string $filename): bool - { - $process = $this->_exec($this->_getExportExecutable($filename)); - Exceptionist::isTrue($process->isSuccessful(), __d('database_backup', 'Export failed with error message: `{0}`', rtrim($process->getErrorOutput()))); - - return file_exists($filename); - } - - /** - * Imports the database - * @param string $filename Filename from which you want to import the database - * @return bool `true` on success - * @throws \Tools\Exception\NotInArrayException - * @throws \ReflectionException - * @throws \ErrorException - */ - final public function import(string $filename): bool - { - $process = $this->_exec($this->_getImportExecutable($filename)); - Exceptionist::isTrue($process->isSuccessful(), __d('database_backup', 'Import failed with error message: `{0}`', rtrim($process->getErrorOutput()))); - - return true; - } } diff --git a/src/TestSuite/DriverTestCase.php b/src/TestSuite/DriverTestCase.php index e22d7f9c..cbff5b15 100644 --- a/src/TestSuite/DriverTestCase.php +++ b/src/TestSuite/DriverTestCase.php @@ -1,4 +1,5 @@ - */ - protected string $DriverClass; - - /** - * Name of the database connection - * @var string - */ - protected string $connection; - - /** - * @var array - */ - public $fixtures = ['core.Articles', 'core.Comments']; /** * Called before every test method @@ -73,102 +45,10 @@ public function setUp(): void /** @var \Cake\Database\Connection $connection */ $connection = $this->getConnection('test'); - foreach (['Articles', 'Comments'] as $name) { - $this->{$name} ??= $this->getTable($name, compact('connection')); - } - if (empty($this->DriverClass) || empty($this->Driver)) { /** @var class-string<\DatabaseBackup\Driver\Driver> $DriverClass */ - $DriverClass = 'DatabaseBackup\\Driver\\' . array_value_last(explode('\\', $connection->config()['driver'])); - $this->DriverClass = $DriverClass; - $this->Driver = new $this->DriverClass($connection); - } - - //Enables event tracking - $this->Driver->getEventManager()->setEventList(new EventList()); - } - - /** - * Internal method to get all records from the database - * @return array - */ - final protected function getAllRecords(): array - { - foreach (['Articles', 'Comments'] as $name) { - $records[$name] = $this->{$name}->find()->enableHydration(false)->toArray(); - } - - return $records; - } - - /** - * @return void - * @throws \Exception - * @uses \DatabaseBackup\Driver\Driver::export() - */ - public function testExport(): void - { - $backup = $this->getAbsolutePath('example.sql'); - $this->assertFileDoesNotExist($backup); - $this->Driver->dispatchEvent('Backup.beforeExport'); - $this->assertTrue($this->Driver->export($backup)); - $this->assertFileExists($backup); - } - - /** - * Test for `export()` and `import()` methods. It tests that the backup is properly exported and then imported. - * @return void - * @throws \Exception - * @uses \DatabaseBackup\Driver\Driver::import() - * @uses \DatabaseBackup\Driver\Driver::export() - */ - public function testExportAndImport(): void - { - foreach (DATABASE_BACKUP_EXTENSIONS as $extension) { - $backup = uniqid('example_'); - $backup = $this->getAbsolutePath($extension ? $backup . '.' . $extension : $backup); - - //Initial records. 3 articles and 6 comments - $initial = $this->getAllRecords(); - $this->assertCount(3, $initial['Articles']); - $this->assertCount(6, $initial['Comments']); - - //Exports backup and deletes article with ID 2 and comment with ID 4 - $this->Driver->dispatchEvent('Backup.beforeExport'); - $this->assertTrue($this->Driver->export($backup)); - $this->Driver->dispatchEvent('Backup.afterExport'); - $this->Articles->delete($this->Articles->get(2), ['atomic' => false]); - $this->Comments->delete($this->Comments->get(4), ['atomic' => false]); - - //Records after delete. 2 articles and 5 comments - $afterDelete = $this->getAllRecords(); - $this->assertCount(count($initial['Articles']) - 1, $afterDelete['Articles']); - $this->assertCount(count($initial['Comments']) - 1, $afterDelete['Comments']); - - //Imports backup. Now initial records are the same of final records - $this->Driver->dispatchEvent('Backup.beforeImport'); - $this->assertTrue($this->Driver->import($backup)); - $this->Driver->dispatchEvent('Backup.afterImport'); - $final = $this->getAllRecords(); - $this->assertEquals($initial, $final); - - //Gets the difference (`$diff`) between records after delete and records after import (`$final`) - $diff = $final; - foreach ($final as $model => $finalValues) { - foreach ($finalValues as $finalKey => $finalValue) { - foreach ($afterDelete[$model] as $deletedValue) { - if ($finalValue == $deletedValue) { - unset($diff[$model][$finalKey]); - } - } - } - } - $this->assertCount(1, $diff['Articles']); - $this->assertCount(1, $diff['Comments']); - - //Difference is article with ID 2 and comment with ID 4 - $this->assertSame(2, collection($diff['Articles'])->extract('id')->first()); - $this->assertSame(4, collection($diff['Comments'])->extract('id')->first()); + $DriverClass = 'DatabaseBackup\\Driver\\' . get_class_short_name($connection->config()['driver']); + $this->Driver = new $DriverClass($connection); } } @@ -189,21 +69,6 @@ public function testGetExportExecutable(): void } } - /** - * @return void - * @throws \Exception - * @uses \DatabaseBackup\Driver\Driver::import() - */ - public function testImport(): void - { - $backup = $this->getAbsolutePath('example.sql'); - $this->Driver->dispatchEvent('Backup.beforeExport'); - $this->assertTrue($this->Driver->export($backup)); - $this->Driver->dispatchEvent('Backup.afterExport'); - $this->Driver->dispatchEvent('Backup.beforeImport'); - $this->assertTrue($this->Driver->import($backup)); - } - /** * @return void * @throws \ReflectionException|\ErrorException diff --git a/src/Utility/BackupExport.php b/src/Utility/BackupExport.php index e6d6d5bb..51fa7780 100644 --- a/src/Utility/BackupExport.php +++ b/src/Utility/BackupExport.php @@ -210,7 +210,8 @@ public function export() } //Exports - $this->Driver->export($filename); + $Process = $this->Driver->_exec($this->Driver->_getExportExecutable($filename)); + Exceptionist::isTrue($Process->isSuccessful(), __d('database_backup', 'Export failed with error message: `{0}`', rtrim($Process->getErrorOutput()))); Filesystem::instance()->chmod($filename, Configure::read('DatabaseBackup.chmod')); //Dispatches the `Backup.afterExport` event implemented by the driver diff --git a/src/Utility/BackupImport.php b/src/Utility/BackupImport.php index 9710639f..844a2951 100644 --- a/src/Utility/BackupImport.php +++ b/src/Utility/BackupImport.php @@ -94,7 +94,9 @@ public function import() } //Imports - $this->Driver->import($filename); + $Process = $this->Driver->_exec($this->Driver->_getImportExecutable($filename)); + Exceptionist::isTrue($Process->isSuccessful(), __d('database_backup', 'Import failed with error message: `{0}`', rtrim($Process->getErrorOutput()))); +// $this->Driver->import($filename); //Dispatches the `Backup.afterImport` event implemented by the driver $this->Driver->dispatchEvent('Backup.afterImport'); diff --git a/tests/TestCase/Driver/DriverTest.php b/tests/TestCase/Driver/DriverTest.php index 1b358684..abc9bdeb 100644 --- a/tests/TestCase/Driver/DriverTest.php +++ b/tests/TestCase/Driver/DriverTest.php @@ -18,8 +18,6 @@ use DatabaseBackup\Driver\Driver; use DatabaseBackup\TestSuite\TestCase; -use Symfony\Component\Process\Exception\ProcessTimedOutException; -use Symfony\Component\Process\Process; /** * DriverTest class. @@ -68,64 +66,4 @@ public function testGetConfig(): void $this->assertNotEmpty($this->Driver->getConfig('name')); $this->assertNull($this->Driver->getConfig('noExistingKey')); } - - /** - * @test - * @uses \DatabaseBackup\Driver\Driver::export() - */ - public function testExportOnFailure(): void - { - $expectedError = 'mysqldump: Got error: 1044: "Access denied for user \'root\'@\'localhost\' to database \'noExisting\'" when selecting the database'; - - $this->expectExceptionMessage('Export failed with error message: `' . $expectedError . '`'); - $Driver = $this->getMockForAbstractDriverWithErrorProcess($expectedError); - $Driver->export($this->getAbsolutePath('example.sql')); - } - - /** - * Test for `export()` method, exceeding the timeout - * @see https://symfony.com/doc/current/components/process.html#process-timeout - * @test - * @uses \DatabaseBackup\Driver\Driver::_exec() - * @uses \DatabaseBackup\Driver\Driver::export() - */ - public function testExportExceedingTimeout(): void - { - $this->expectException(ProcessTimedOutException::class); - $this->expectExceptionMessage('The process "dir" exceeded the timeout of 60 seconds'); - $ProcessTimedOutException = new ProcessTimedOutException(Process::fromShellCommandline('dir'), 1); - $Driver = $this->getMockForAbstractDriver(['_exec']); - $Driver->method('_exec')->willThrowException($ProcessTimedOutException); - $Driver->export($this->getAbsolutePath('example.sql')); - } - - /** - * Test for `import()` method on failure - * @test - * @uses \DatabaseBackup\Driver\Driver::import() - */ - public function testImportOnFailure(): void - { - $expectedError = 'ERROR 1044 (42000): Access denied for user \'root\'@\'localhost\' to database \'noExisting\''; - $this->expectExceptionMessage('Import failed with error message: `' . $expectedError . '`'); - $Driver = $this->getMockForAbstractDriverWithErrorProcess($expectedError); - $Driver->import($this->getAbsolutePath('example.sql')); - } - - /** - * Test for `import()` method, exceeding the timeout - * @see https://symfony.com/doc/current/components/process.html#process-timeout - * @test - * @uses \DatabaseBackup\Driver\Driver::_exec() - * @uses \DatabaseBackup\Driver\Driver::import() - */ - public function testImportExceedingTimeout(): void - { - $this->expectException(ProcessTimedOutException::class); - $this->expectExceptionMessage('The process "dir" exceeded the timeout of 60 seconds'); - $ProcessTimedOutException = new ProcessTimedOutException(Process::fromShellCommandline('dir'), 1); - $Driver = $this->getMockForAbstractDriver(['_exec']); - $Driver->method('_exec')->willThrowException($ProcessTimedOutException); - $Driver->import($this->getAbsolutePath('example.sql')); - } } diff --git a/tests/TestCase/Utility/BackupExportTest.php b/tests/TestCase/Utility/BackupExportTest.php index 6dbf3d10..10330bcb 100644 --- a/tests/TestCase/Utility/BackupExportTest.php +++ b/tests/TestCase/Utility/BackupExportTest.php @@ -20,6 +20,8 @@ use Cake\TestSuite\EmailTrait; use DatabaseBackup\TestSuite\TestCase; use DatabaseBackup\Utility\BackupExport; +use Symfony\Component\Process\Exception\ProcessTimedOutException; +use Symfony\Component\Process\Process; use Tools\TestSuite\ReflectionTrait; /** @@ -192,4 +194,33 @@ public function testExportStoppedByBeforeExport(): void $this->BackupExport->Driver = $Driver; $this->assertFalse($this->BackupExport->export()); } + + /** + * Test for `export()` method, on failure (error for `Process`) + * @test + * @uses \DatabaseBackup\Utility\BackupExport::export() + */ + public function testExportOnFailure(): void + { + $expectedError = 'mysqldump: Got error: 1044: "Access denied for user \'root\'@\'localhost\' to database \'noExisting\'" when selecting the database'; + $this->expectExceptionMessage('Export failed with error message: `' . $expectedError . '`'); + $this->BackupExport->Driver = $this->getMockForAbstractDriverWithErrorProcess($expectedError); + $this->BackupExport->export(); + } + + /** + * Test for `export()` method, exceeding the timeout + * @see https://symfony.com/doc/current/components/process.html#process-timeout + * @test + * @uses \DatabaseBackup\Utility\BackupExport::export() + */ + public function testExportExceedingTimeout(): void + { + $this->expectException(ProcessTimedOutException::class); + $this->expectExceptionMessage('The process "dir" exceeded the timeout of 60 seconds'); + $ProcessTimedOutException = new ProcessTimedOutException(Process::fromShellCommandline('dir'), 1); + $this->BackupExport->Driver = $this->getMockForAbstractDriver(['_exec']); + $this->BackupExport->Driver->method('_exec')->willThrowException($ProcessTimedOutException); + $this->BackupExport->export(); + } } diff --git a/tests/TestCase/Utility/BackupImportTest.php b/tests/TestCase/Utility/BackupImportTest.php index b476641d..80d5e992 100644 --- a/tests/TestCase/Utility/BackupImportTest.php +++ b/tests/TestCase/Utility/BackupImportTest.php @@ -18,6 +18,8 @@ use Cake\Event\EventList; use DatabaseBackup\TestSuite\TestCase; use DatabaseBackup\Utility\BackupImport; +use Symfony\Component\Process\Exception\ProcessTimedOutException; +use Symfony\Component\Process\Process; use Tools\Exception\NotReadableException; use Tools\Filesystem; use Tools\TestSuite\ReflectionTrait; @@ -106,4 +108,35 @@ public function testImportStoppedByBeforeExport(): void $this->BackupImport->filename(createBackup()); $this->assertFalse($this->BackupImport->import()); } + + /** + * Test for `import()` method, on failure (error for `Process`) + * @test + * @uses \DatabaseBackup\Utility\BackupImport::import() + */ + public function testImportOnFailure(): void + { + $expectedError = 'ERROR 1044 (42000): Access denied for user \'root\'@\'localhost\' to database \'noExisting\''; + $this->expectExceptionMessage('Import failed with error message: `' . $expectedError . '`'); + $this->BackupImport->Driver = $this->getMockForAbstractDriverWithErrorProcess($expectedError); + $this->BackupImport->filename(createBackup()); + $this->BackupImport->import(); + } + + /** + * Test for `import()` method, exceeding the timeout + * @see https://symfony.com/doc/current/components/process.html#process-timeout + * @test + * @uses \DatabaseBackup\Utility\BackupImport::import() + */ + public function testImportExceedingTimeout(): void + { + $this->expectException(ProcessTimedOutException::class); + $this->expectExceptionMessage('The process "dir" exceeded the timeout of 60 seconds'); + $ProcessTimedOutException = new ProcessTimedOutException(Process::fromShellCommandline('dir'), 1); + $this->BackupImport->Driver = $this->getMockForAbstractDriver(['_exec']); + $this->BackupImport->Driver->method('_exec')->willThrowException($ProcessTimedOutException); + $this->BackupImport->filename(createBackup()); + $this->BackupImport->import(); + } } From b729a7f5808a92da74eba648697d13d129e60b86 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sat, 3 Jun 2023 19:04:47 +0200 Subject: [PATCH 07/52] moved tests --- .../Utility/BackupExportAndImportTest.php | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 tests/TestCase/Utility/BackupExportAndImportTest.php diff --git a/tests/TestCase/Utility/BackupExportAndImportTest.php b/tests/TestCase/Utility/BackupExportAndImportTest.php new file mode 100644 index 00000000..4bdf319d --- /dev/null +++ b/tests/TestCase/Utility/BackupExportAndImportTest.php @@ -0,0 +1,122 @@ + + */ + public $fixtures = ['core.Articles', 'core.Comments']; + + /** + * Internal method to get all records from the database + * @return array + */ + protected function getAllRecords(): array + { + foreach (['Articles', 'Comments'] as $name) { + $records[$name] = $this->{$name}->find()->enableHydration(false)->toArray(); + } + + return $records; + } + + /** + * Called before every test method + * @return void + */ + public function setUp(): void + { + parent::setUp(); + + /** @var \Cake\Database\Connection $connection */ + $connection = $this->getConnection('test'); + foreach (['Articles', 'Comments'] as $name) { + $this->{$name} ??= $this->getTable($name, compact('connection')); + } + } + + /** + * Test for `export()` and `import()` methods. It tests that the backup is properly exported and then imported + * @uses \DatabaseBackup\Utility\BackupExport::export() + * @uses \DatabaseBackup\Utility\BackupImport::import() + */ + public function testExportAndImport(): void + { + $BackupExport = new BackupExport(); + $BackupImport = new BackupImport(); + + foreach (array_keys(DATABASE_BACKUP_EXTENSIONS) as $extension) { + $expectedFilename = $this->getAbsolutePath(uniqid('example_') . '.' . $extension); + + //Initial records. 3 articles and 6 comments + $initial = $this->getAllRecords(); + $this->assertCount(3, $initial['Articles']); + $this->assertCount(6, $initial['Comments']); + + //Exports backup and deletes article with ID 2 and comment with ID 4 + $result = $BackupExport->filename($expectedFilename)->export(); + $this->assertSame($expectedFilename, $result); + $this->Articles->delete($this->Articles->get(2), ['atomic' => false]); + $this->Comments->delete($this->Comments->get(4), ['atomic' => false]); + + //Records after delete. 2 articles and 5 comments + $afterDelete = $this->getAllRecords(); + $this->assertCount(count($initial['Articles']) - 1, $afterDelete['Articles']); + $this->assertCount(count($initial['Comments']) - 1, $afterDelete['Comments']); + + //Imports backup. Now initial records are the same of final records + $result = $BackupImport->filename($expectedFilename)->import(); + $this->assertSame($expectedFilename, $result); + $final = $this->getAllRecords(); + $this->assertEquals($initial, $final); + + //Gets the difference (`$diff`) between records after delete and records after import (`$final`) + $diff = $final; + foreach ($final as $model => $finalValues) { + foreach ($finalValues as $finalKey => $finalValue) { + foreach ($afterDelete[$model] as $deletedValue) { + if ($finalValue == $deletedValue) { + unset($diff[$model][$finalKey]); + } + } + } + } + $this->assertCount(1, $diff['Articles']); + $this->assertCount(1, $diff['Comments']); + + //Difference is article with ID 2 and comment with ID 4 + $this->assertSame([2], array_column($diff['Articles'], 'id')); + $this->assertSame([4], array_column($diff['Comments'], 'id')); + } + } +} From 0567f52ab58322a06ad64ac51cbf60d94286ccd8 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sat, 3 Jun 2023 19:20:45 +0200 Subject: [PATCH 08/52] added the `AbstractBackupUtility` abstract class that provides the code common to `BackupExport` and `BackupImport` --- CHANGELOG.md | 1 + src/Utility/AbstractBackupUtility.php | 48 +++++++++++++++++++++++++++ src/Utility/BackupExport.php | 19 +---------- src/Utility/BackupImport.php | 19 +---------- 4 files changed, 51 insertions(+), 36 deletions(-) create mode 100644 src/Utility/AbstractBackupUtility.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 10567bea..7bb300b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ methods, and no longer by the drivers themselves; * the `BackupExport::export()` and `BackupImport::import()` methods can return the filename path on success or `false` if the `Backup.beforeExport`/`Backup.beforeImport` events are stopped; +* added the `AbstractBackupUtility` abstract class that provides the code common to `BackupExport` and `BackupImport`; * the code of `Driver::export()` and `Driver::import()` methods has been absorbed by `BackupExport::export()` and `BackupImport::import()` and therefore those methods no longer exist; * completely improved the `BackupImportTest` tests. diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php new file mode 100644 index 00000000..e64ceacf --- /dev/null +++ b/src/Utility/AbstractBackupUtility.php @@ -0,0 +1,48 @@ +Driver->_exec($this->Driver->_getImportExecutable($filename)); Exceptionist::isTrue($Process->isSuccessful(), __d('database_backup', 'Import failed with error message: `{0}`', rtrim($Process->getErrorOutput()))); -// $this->Driver->import($filename); //Dispatches the `Backup.afterImport` event implemented by the driver $this->Driver->dispatchEvent('Backup.afterImport'); From ee51f8ea1782562376ae6b7d19096c390f497bb2 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sat, 3 Jun 2023 19:32:24 +0200 Subject: [PATCH 09/52] `Driver::_exec()` method has been moved to the `AbstractBackupUtility` class --- CHANGELOG.md | 3 ++- src/Driver/Driver.php | 16 ---------------- src/Utility/AbstractBackupUtility.php | 17 +++++++++++++++++ src/Utility/BackupExport.php | 2 +- src/Utility/BackupImport.php | 2 +- tests/TestCase/Utility/BackupExportTest.php | 16 +++++++++++----- tests/TestCase/Utility/BackupImportTest.php | 18 +++++++++++------- 7 files changed, 43 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bb300b0..c03d1440 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,10 @@ * the events (`Backup.beforeExport`, `Backup.afterExport`, `Backup.beforeImport`, `Backup.afterImport`, which remain implemented by the driver classes) are directly dispatched by the `BackupExport::export()` and `BackupImport::import()` methods, and no longer by the drivers themselves; +* added the `AbstractBackupUtility` abstract class that provides the code common to `BackupExport` and `BackupImport`; +* `Driver::_exec()` method has been moved to the `AbstractBackupUtility` class; * the `BackupExport::export()` and `BackupImport::import()` methods can return the filename path on success or `false` if the `Backup.beforeExport`/`Backup.beforeImport` events are stopped; -* added the `AbstractBackupUtility` abstract class that provides the code common to `BackupExport` and `BackupImport`; * the code of `Driver::export()` and `Driver::import()` methods has been absorbed by `BackupExport::export()` and `BackupImport::import()` and therefore those methods no longer exist; * completely improved the `BackupImportTest` tests. diff --git a/src/Driver/Driver.php b/src/Driver/Driver.php index 5a31dd3f..7a1656a4 100644 --- a/src/Driver/Driver.php +++ b/src/Driver/Driver.php @@ -20,7 +20,6 @@ use Cake\Event\EventDispatcherTrait; use Cake\Event\EventListenerInterface; use DatabaseBackup\BackupTrait; -use Symfony\Component\Process\Process; use Tools\Exceptionist; /** @@ -66,21 +65,6 @@ final public function implementedEvents(): array ]; } - /** - * Internal method to run and get a `Process` instance as a command-line to be run in a shell wrapper. - * @param string $command The command line to pass to the shell of the OS - * @return \Symfony\Component\Process\Process - * @since 2.8.7 - */ - public function _exec(string $command): Process - { - $Process = Process::fromShellCommandline($command); - $Process->setTimeout(Configure::read('DatabaseBackup.processTimeout', 60)); - $Process->run(); - - return $Process; - } - /** * Gets and parses executable commands from the configuration, according to the type of requested operation * (`export` or `import`) and the connection driver. diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index e64ceacf..305e2db3 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -15,8 +15,10 @@ */ namespace DatabaseBackup\Utility; +use Cake\Core\Configure; use DatabaseBackup\BackupTrait; use DatabaseBackup\Driver\Driver; +use Symfony\Component\Process\Process; /** * AbstractBackupUtility. @@ -45,4 +47,19 @@ abstract class AbstractBackupUtility * @return $this */ abstract function filename(string $filename); + + /** + * Internal method to run and get a `Process` instance as a command-line to be run in a shell wrapper. + * @param string $command The command line to pass to the shell of the OS + * @return \Symfony\Component\Process\Process + * @since 2.8.7 + */ + public function _exec(string $command): Process + { + $Process = Process::fromShellCommandline($command); + $Process->setTimeout(Configure::read('DatabaseBackup.processTimeout', 60)); + $Process->run(); + + return $Process; + } } diff --git a/src/Utility/BackupExport.php b/src/Utility/BackupExport.php index 138c614b..a53103dc 100644 --- a/src/Utility/BackupExport.php +++ b/src/Utility/BackupExport.php @@ -193,7 +193,7 @@ public function export() } //Exports - $Process = $this->Driver->_exec($this->Driver->_getExportExecutable($filename)); + $Process = $this->_exec($this->Driver->_getExportExecutable($filename)); Exceptionist::isTrue($Process->isSuccessful(), __d('database_backup', 'Export failed with error message: `{0}`', rtrim($Process->getErrorOutput()))); Filesystem::instance()->chmod($filename, Configure::read('DatabaseBackup.chmod')); diff --git a/src/Utility/BackupImport.php b/src/Utility/BackupImport.php index c7aa4016..75a2f7df 100644 --- a/src/Utility/BackupImport.php +++ b/src/Utility/BackupImport.php @@ -78,7 +78,7 @@ public function import() } //Imports - $Process = $this->Driver->_exec($this->Driver->_getImportExecutable($filename)); + $Process = $this->_exec($this->Driver->_getImportExecutable($filename)); Exceptionist::isTrue($Process->isSuccessful(), __d('database_backup', 'Import failed with error message: `{0}`', rtrim($Process->getErrorOutput()))); //Dispatches the `Backup.afterImport` event implemented by the driver diff --git a/tests/TestCase/Utility/BackupExportTest.php b/tests/TestCase/Utility/BackupExportTest.php index 10330bcb..25e1b910 100644 --- a/tests/TestCase/Utility/BackupExportTest.php +++ b/tests/TestCase/Utility/BackupExportTest.php @@ -204,8 +204,12 @@ public function testExportOnFailure(): void { $expectedError = 'mysqldump: Got error: 1044: "Access denied for user \'root\'@\'localhost\' to database \'noExisting\'" when selecting the database'; $this->expectExceptionMessage('Export failed with error message: `' . $expectedError . '`'); - $this->BackupExport->Driver = $this->getMockForAbstractDriverWithErrorProcess($expectedError); - $this->BackupExport->export(); + $Process = $this->createConfiguredMock(Process::class, ['getErrorOutput' => $expectedError . PHP_EOL, 'isSuccessful' => false]); + $BackupExport = $this->getMockBuilder(BackupExport::class) + ->onlyMethods(['_exec']) + ->getMock(); + $BackupExport->method('_exec')->willReturn($Process); + $BackupExport->export(); } /** @@ -219,8 +223,10 @@ public function testExportExceedingTimeout(): void $this->expectException(ProcessTimedOutException::class); $this->expectExceptionMessage('The process "dir" exceeded the timeout of 60 seconds'); $ProcessTimedOutException = new ProcessTimedOutException(Process::fromShellCommandline('dir'), 1); - $this->BackupExport->Driver = $this->getMockForAbstractDriver(['_exec']); - $this->BackupExport->Driver->method('_exec')->willThrowException($ProcessTimedOutException); - $this->BackupExport->export(); + $BackupExport = $this->getMockBuilder(BackupExport::class) + ->onlyMethods(['_exec']) + ->getMock(); + $BackupExport->method('_exec')->willThrowException($ProcessTimedOutException); + $BackupExport->export(); } } diff --git a/tests/TestCase/Utility/BackupImportTest.php b/tests/TestCase/Utility/BackupImportTest.php index 80d5e992..4d8211f3 100644 --- a/tests/TestCase/Utility/BackupImportTest.php +++ b/tests/TestCase/Utility/BackupImportTest.php @@ -118,9 +118,12 @@ public function testImportOnFailure(): void { $expectedError = 'ERROR 1044 (42000): Access denied for user \'root\'@\'localhost\' to database \'noExisting\''; $this->expectExceptionMessage('Import failed with error message: `' . $expectedError . '`'); - $this->BackupImport->Driver = $this->getMockForAbstractDriverWithErrorProcess($expectedError); - $this->BackupImport->filename(createBackup()); - $this->BackupImport->import(); + $Process = $this->createConfiguredMock(Process::class, ['getErrorOutput' => $expectedError . PHP_EOL, 'isSuccessful' => false]); + $BackupImport = $this->getMockBuilder(BackupImport::class) + ->onlyMethods(['_exec']) + ->getMock(); + $BackupImport->method('_exec')->willReturn($Process); + $BackupImport->filename(createBackup())->import(); } /** @@ -134,9 +137,10 @@ public function testImportExceedingTimeout(): void $this->expectException(ProcessTimedOutException::class); $this->expectExceptionMessage('The process "dir" exceeded the timeout of 60 seconds'); $ProcessTimedOutException = new ProcessTimedOutException(Process::fromShellCommandline('dir'), 1); - $this->BackupImport->Driver = $this->getMockForAbstractDriver(['_exec']); - $this->BackupImport->Driver->method('_exec')->willThrowException($ProcessTimedOutException); - $this->BackupImport->filename(createBackup()); - $this->BackupImport->import(); + $BackupImport = $this->getMockBuilder(BackupImport::class) + ->onlyMethods(['_exec']) + ->getMock(); + $BackupImport->method('_exec')->willThrowException($ProcessTimedOutException); + $BackupImport->filename(createBackup())->import(); } } From 12c59965464060a6972380be26c18ec36164adb8 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sat, 3 Jun 2023 19:34:45 +0200 Subject: [PATCH 10/52] `Driver::_exec()` method has become `AbstractBackupUtility::getProcess()` --- CHANGELOG.md | 2 +- src/TestSuite/TestCase.php | 16 ---------------- src/Utility/AbstractBackupUtility.php | 2 +- src/Utility/BackupExport.php | 2 +- src/Utility/BackupImport.php | 2 +- tests/TestCase/Utility/BackupExportTest.php | 8 ++++---- tests/TestCase/Utility/BackupImportTest.php | 8 ++++---- 7 files changed, 12 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c03d1440..c54d64a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ implemented by the driver classes) are directly dispatched by the `BackupExport::export()` and `BackupImport::import()` methods, and no longer by the drivers themselves; * added the `AbstractBackupUtility` abstract class that provides the code common to `BackupExport` and `BackupImport`; -* `Driver::_exec()` method has been moved to the `AbstractBackupUtility` class; +* `Driver::_exec()` method has become `AbstractBackupUtility::getProcess()`; * the `BackupExport::export()` and `BackupImport::import()` methods can return the filename path on success or `false` if the `Backup.beforeExport`/`Backup.beforeImport` events are stopped; * the code of `Driver::export()` and `Driver::import()` methods has been absorbed by `BackupExport::export()` and diff --git a/src/TestSuite/TestCase.php b/src/TestSuite/TestCase.php index 53d52415..d97bdfff 100644 --- a/src/TestSuite/TestCase.php +++ b/src/TestSuite/TestCase.php @@ -19,7 +19,6 @@ use DatabaseBackup\Driver\Driver; use DatabaseBackup\Utility\BackupManager; use MeTools\TestSuite\TestCase as BaseTestCase; -use Symfony\Component\Process\Process; /** * TestCase class @@ -53,19 +52,4 @@ protected function getMockForAbstractDriver(array $mockedMethods = []): Driver return $Driver; } - - /** - * Internal method to get a mock for `Driver` abstract class, with the `_exec()` method that returns a `Process` - * instance with a failure and a custom error message - * @param string $errorMessage The error message - * @return \DatabaseBackup\Driver\Driver&\PHPUnit\Framework\MockObject\MockObject - */ - protected function getMockForAbstractDriverWithErrorProcess(string $errorMessage): Driver - { - $Process = $this->createConfiguredMock(Process::class, ['getErrorOutput' => $errorMessage . PHP_EOL, 'isSuccessful' => false]); - $Driver = $this->getMockForAbstractDriver(['_exec']); - $Driver->method('_exec')->willReturn($Process); - - return $Driver; - } } diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index 305e2db3..05ebfbc3 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -54,7 +54,7 @@ abstract function filename(string $filename); * @return \Symfony\Component\Process\Process * @since 2.8.7 */ - public function _exec(string $command): Process + protected function getProcess(string $command): Process { $Process = Process::fromShellCommandline($command); $Process->setTimeout(Configure::read('DatabaseBackup.processTimeout', 60)); diff --git a/src/Utility/BackupExport.php b/src/Utility/BackupExport.php index a53103dc..f64e37fc 100644 --- a/src/Utility/BackupExport.php +++ b/src/Utility/BackupExport.php @@ -193,7 +193,7 @@ public function export() } //Exports - $Process = $this->_exec($this->Driver->_getExportExecutable($filename)); + $Process = $this->getProcess($this->Driver->_getExportExecutable($filename)); Exceptionist::isTrue($Process->isSuccessful(), __d('database_backup', 'Export failed with error message: `{0}`', rtrim($Process->getErrorOutput()))); Filesystem::instance()->chmod($filename, Configure::read('DatabaseBackup.chmod')); diff --git a/src/Utility/BackupImport.php b/src/Utility/BackupImport.php index 75a2f7df..18c4ca47 100644 --- a/src/Utility/BackupImport.php +++ b/src/Utility/BackupImport.php @@ -78,7 +78,7 @@ public function import() } //Imports - $Process = $this->_exec($this->Driver->_getImportExecutable($filename)); + $Process = $this->getProcess($this->Driver->_getImportExecutable($filename)); Exceptionist::isTrue($Process->isSuccessful(), __d('database_backup', 'Import failed with error message: `{0}`', rtrim($Process->getErrorOutput()))); //Dispatches the `Backup.afterImport` event implemented by the driver diff --git a/tests/TestCase/Utility/BackupExportTest.php b/tests/TestCase/Utility/BackupExportTest.php index 25e1b910..872e8d19 100644 --- a/tests/TestCase/Utility/BackupExportTest.php +++ b/tests/TestCase/Utility/BackupExportTest.php @@ -206,9 +206,9 @@ public function testExportOnFailure(): void $this->expectExceptionMessage('Export failed with error message: `' . $expectedError . '`'); $Process = $this->createConfiguredMock(Process::class, ['getErrorOutput' => $expectedError . PHP_EOL, 'isSuccessful' => false]); $BackupExport = $this->getMockBuilder(BackupExport::class) - ->onlyMethods(['_exec']) + ->onlyMethods(['getProcess']) ->getMock(); - $BackupExport->method('_exec')->willReturn($Process); + $BackupExport->method('getProcess')->willReturn($Process); $BackupExport->export(); } @@ -224,9 +224,9 @@ public function testExportExceedingTimeout(): void $this->expectExceptionMessage('The process "dir" exceeded the timeout of 60 seconds'); $ProcessTimedOutException = new ProcessTimedOutException(Process::fromShellCommandline('dir'), 1); $BackupExport = $this->getMockBuilder(BackupExport::class) - ->onlyMethods(['_exec']) + ->onlyMethods(['getProcess']) ->getMock(); - $BackupExport->method('_exec')->willThrowException($ProcessTimedOutException); + $BackupExport->method('getProcess')->willThrowException($ProcessTimedOutException); $BackupExport->export(); } } diff --git a/tests/TestCase/Utility/BackupImportTest.php b/tests/TestCase/Utility/BackupImportTest.php index 4d8211f3..e7f8cdd5 100644 --- a/tests/TestCase/Utility/BackupImportTest.php +++ b/tests/TestCase/Utility/BackupImportTest.php @@ -120,9 +120,9 @@ public function testImportOnFailure(): void $this->expectExceptionMessage('Import failed with error message: `' . $expectedError . '`'); $Process = $this->createConfiguredMock(Process::class, ['getErrorOutput' => $expectedError . PHP_EOL, 'isSuccessful' => false]); $BackupImport = $this->getMockBuilder(BackupImport::class) - ->onlyMethods(['_exec']) + ->onlyMethods(['getProcess']) ->getMock(); - $BackupImport->method('_exec')->willReturn($Process); + $BackupImport->method('getProcess')->willReturn($Process); $BackupImport->filename(createBackup())->import(); } @@ -138,9 +138,9 @@ public function testImportExceedingTimeout(): void $this->expectExceptionMessage('The process "dir" exceeded the timeout of 60 seconds'); $ProcessTimedOutException = new ProcessTimedOutException(Process::fromShellCommandline('dir'), 1); $BackupImport = $this->getMockBuilder(BackupImport::class) - ->onlyMethods(['_exec']) + ->onlyMethods(['getProcess']) ->getMock(); - $BackupImport->method('_exec')->willThrowException($ProcessTimedOutException); + $BackupImport->method('getProcess')->willThrowException($ProcessTimedOutException); $BackupImport->filename(createBackup())->import(); } } From bd9c3c2ef0200e8a68b13d38fd6c727bfb95f5ad Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sat, 3 Jun 2023 19:37:10 +0200 Subject: [PATCH 11/52] fixed tests --- tests/TestCase/Utility/BackupExportTest.php | 5 ++--- tests/TestCase/Utility/BackupImportTest.php | 8 +++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/tests/TestCase/Utility/BackupExportTest.php b/tests/TestCase/Utility/BackupExportTest.php index 872e8d19..c52f653e 100644 --- a/tests/TestCase/Utility/BackupExportTest.php +++ b/tests/TestCase/Utility/BackupExportTest.php @@ -189,9 +189,8 @@ public function testExportWithDifferentChmod(): void */ public function testExportStoppedByBeforeExport(): void { - $Driver = $this->getMockForAbstractDriver(['beforeExport']); - $Driver->method('beforeExport')->willReturn(false); - $this->BackupExport->Driver = $Driver; + $this->BackupExport->Driver = $this->getMockForAbstractDriver(['beforeExport']); + $this->BackupExport->Driver->method('beforeExport')->willReturn(false); $this->assertFalse($this->BackupExport->export()); } diff --git a/tests/TestCase/Utility/BackupImportTest.php b/tests/TestCase/Utility/BackupImportTest.php index e7f8cdd5..7bfe8329 100644 --- a/tests/TestCase/Utility/BackupImportTest.php +++ b/tests/TestCase/Utility/BackupImportTest.php @@ -102,11 +102,9 @@ public function testImport(): void */ public function testImportStoppedByBeforeExport(): void { - $Driver = $this->getMockForAbstractDriver(['beforeImport']); - $Driver->method('beforeImport')->willReturn(false); - $this->BackupImport->Driver = $Driver; - $this->BackupImport->filename(createBackup()); - $this->assertFalse($this->BackupImport->import()); + $this->BackupImport->Driver = $this->getMockForAbstractDriver(['beforeImport']); + $this->BackupImport->Driver->method('beforeImport')->willReturn(false); + $this->assertFalse($this->BackupImport->filename(createBackup())->import()); } /** From 1ad388caa91ddb255c832945bfc34613b9c5f4c2 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sat, 3 Jun 2023 19:49:03 +0200 Subject: [PATCH 12/52] `BackupTrait::getDriver()` method has become `AbstractBackupUtility::getDriver()` --- CHANGELOG.md | 1 + src/BackupTrait.php | 23 ----------------------- src/Utility/AbstractBackupUtility.php | 23 +++++++++++++++++++++++ tests/TestCase/BackupTraitTest.php | 18 ------------------ 4 files changed, 24 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c54d64a3..69450a5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ methods, and no longer by the drivers themselves; * added the `AbstractBackupUtility` abstract class that provides the code common to `BackupExport` and `BackupImport`; * `Driver::_exec()` method has become `AbstractBackupUtility::getProcess()`; +* `BackupTrait::getDriver()` method has become `AbstractBackupUtility::getDriver()`; * the `BackupExport::export()` and `BackupImport::import()` methods can return the filename path on success or `false` if the `Backup.beforeExport`/`Backup.beforeImport` events are stopped; * the code of `Driver::export()` and `Driver::import()` methods has been absorbed by `BackupExport::export()` and diff --git a/src/BackupTrait.php b/src/BackupTrait.php index da25d2bd..d89c04a3 100644 --- a/src/BackupTrait.php +++ b/src/BackupTrait.php @@ -14,12 +14,9 @@ */ namespace DatabaseBackup; -use Cake\Core\App; use Cake\Core\Configure; use Cake\Datasource\ConnectionInterface; use Cake\Datasource\ConnectionManager; -use DatabaseBackup\Driver\Driver; -use Tools\Exceptionist; use Tools\Filesystem; /** @@ -61,26 +58,6 @@ public static function getConnection(?string $name = null): ConnectionInterface return ConnectionManager::get($name ?: Configure::readOrFail('DatabaseBackup.connection')); } - /** - * Gets the `Driver` instance, containing all methods to export/import database backups. - * - * You can pass a `Connection` instance. By default, the connection set in the configuration will be used. - * @param \Cake\Datasource\ConnectionInterface|null $connection A `Connection` instance - * @return \DatabaseBackup\Driver\Driver A `Driver` instance - * @throws \ErrorException|\ReflectionException - * @since 2.0.0 - */ - public static function getDriver(?ConnectionInterface $connection = null): Driver - { - $connection = $connection ?: self::getConnection(); - $name = self::getDriverName($connection); - /** @var class-string<\DatabaseBackup\Driver\Driver> $Driver */ - $Driver = App::classname('DatabaseBackup.' . $name, 'Driver'); - Exceptionist::isTrue($Driver, __d('database_backup', 'The `{0}` driver does not exist', $name)); - - return new $Driver($connection); - } - /** * Gets the driver name, according to the connection. * diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index 05ebfbc3..3840d8ff 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -15,10 +15,13 @@ */ namespace DatabaseBackup\Utility; +use Cake\Core\App; use Cake\Core\Configure; +use Cake\Datasource\ConnectionInterface; use DatabaseBackup\BackupTrait; use DatabaseBackup\Driver\Driver; use Symfony\Component\Process\Process; +use Tools\Exceptionist; /** * AbstractBackupUtility. @@ -48,6 +51,26 @@ abstract class AbstractBackupUtility */ abstract function filename(string $filename); + /** + * Gets the `Driver` instance, containing all methods to export/import database backups. + * + * You can pass a `Connection` instance. By default, the connection set in the configuration will be used. + * @param \Cake\Datasource\ConnectionInterface|null $connection A `Connection` instance + * @return \DatabaseBackup\Driver\Driver A `Driver` instance + * @throws \ErrorException|\ReflectionException + * @since 2.0.0 + */ + public function getDriver(?ConnectionInterface $connection = null): Driver + { + $connection = $connection ?: $this->getConnection(); + $name = $this->getDriverName($connection); + /** @var class-string<\DatabaseBackup\Driver\Driver> $Driver */ + $Driver = App::classname('DatabaseBackup.' . $name, 'Driver'); + Exceptionist::isTrue($Driver, __d('database_backup', 'The `{0}` driver does not exist', $name)); + + return new $Driver($connection); + } + /** * Internal method to run and get a `Process` instance as a command-line to be run in a shell wrapper. * @param string $command The command line to pass to the shell of the OS diff --git a/tests/TestCase/BackupTraitTest.php b/tests/TestCase/BackupTraitTest.php index 4315cfbf..ba16919f 100644 --- a/tests/TestCase/BackupTraitTest.php +++ b/tests/TestCase/BackupTraitTest.php @@ -17,11 +17,9 @@ use Cake\Core\Configure; use Cake\Database\Connection; -use Cake\Database\Driver\Sqlserver; use Cake\Datasource\ConnectionManager; use Cake\Datasource\Exception\MissingDatasourceConfigException; use DatabaseBackup\BackupTrait; -use DatabaseBackup\Driver\Driver; use DatabaseBackup\TestSuite\TestCase; /** @@ -102,22 +100,6 @@ public function testGetConnection(): void $this->getConnection('noExisting'); } - /** - * @test - * @uses \DatabaseBackup\BackupTrait::getDriver() - */ - public function testGetDriver(): void - { - foreach ([ConnectionManager::get('test'), null] as $connection) { - $this->assertInstanceof(Driver::class, $this->Trait->getDriver($connection)); - } - - //With a no existing driver - $this->expectExceptionMessage('The `Sqlserver` driver does not exist'); - $Connection = $this->createConfiguredMock(Connection::class, ['__debuginfo' => [], 'getDriver' => new Sqlserver()]); - $this->Trait->getDriver($Connection); - } - /** * @test * @uses \DatabaseBackup\BackupTrait::getExtension() From 468bf333823ba9fb86cd2eeafbc41846266e2359 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sun, 4 Jun 2023 08:26:59 +0200 Subject: [PATCH 13/52] moved code --- src/Utility/AbstractBackupUtility.php | 9 +++++++++ src/Utility/BackupExport.php | 8 ++++---- src/Utility/BackupImport.php | 8 -------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index 3840d8ff..8e7b249e 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -44,6 +44,15 @@ abstract class AbstractBackupUtility */ public Driver $Driver; + /** + * Construct + * @throws \ErrorException|\ReflectionException + */ + public function __construct() + { + $this->Driver = $this->getDriver(); + } + /** * Sets the filename * @param string $filename Filename. It can be an absolute path diff --git a/src/Utility/BackupExport.php b/src/Utility/BackupExport.php index f64e37fc..1c553be0 100644 --- a/src/Utility/BackupExport.php +++ b/src/Utility/BackupExport.php @@ -71,10 +71,10 @@ class BackupExport extends AbstractBackupUtility */ public function __construct() { - $connection = $this->getConnection(); + parent::__construct(); + $this->BackupManager = new BackupManager(); - $this->Driver = $this->getDriver($connection); - $this->config = $connection->config(); + $this->config = $this->getConnection()->config(); } /** @@ -179,7 +179,7 @@ public function export() { if (empty($this->filename)) { $this->extension ??= $this->defaultExtension; - $this->filename(sprintf('backup_{$DATABASE}_{$DATETIME}.%s', $this->extension)); + $this->filename('backup_{$DATABASE}_{$DATETIME}.' . $this->extension); } //This allows the filename to be set again with a next call of this method diff --git a/src/Utility/BackupImport.php b/src/Utility/BackupImport.php index 18c4ca47..6530f78f 100644 --- a/src/Utility/BackupImport.php +++ b/src/Utility/BackupImport.php @@ -22,14 +22,6 @@ */ class BackupImport extends AbstractBackupUtility { - /** - * Construct - * @throws \ErrorException|\ReflectionException - */ - public function __construct() - { - $this->Driver = $this->getDriver(); - } /** * Sets the filename From cc7fd9b256f9cafee4be2b395c5f601175e9e96c Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sun, 4 Jun 2023 08:27:58 +0200 Subject: [PATCH 14/52] removed useless `BackupExport::$config` property --- CHANGELOG.md | 1 + src/Utility/BackupExport.php | 13 ++++--------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69450a5f..15834660 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ if the `Backup.beforeExport`/`Backup.beforeImport` events are stopped; * the code of `Driver::export()` and `Driver::import()` methods has been absorbed by `BackupExport::export()` and `BackupImport::import()` and therefore those methods no longer exist; +* removed useless `BackupExport::$config` property; * completely improved the `BackupImportTest` tests. ## 2.11 branch diff --git a/src/Utility/BackupExport.php b/src/Utility/BackupExport.php index 1c553be0..5077b0f7 100644 --- a/src/Utility/BackupExport.php +++ b/src/Utility/BackupExport.php @@ -35,12 +35,6 @@ class BackupExport extends AbstractBackupUtility */ protected ?string $compression = null; - /** - * Database configuration - * @var array - */ - protected array $config; - /** * Default extension * @var string @@ -74,7 +68,6 @@ public function __construct() parent::__construct(); $this->BackupManager = new BackupManager(); - $this->config = $this->getConnection()->config(); } /** @@ -114,11 +107,13 @@ public function compression(?string $compression) */ public function filename(string $filename) { + $config = $this->getConnection()->config(); + //Replaces patterns $filename = str_replace(['{$DATABASE}', '{$DATETIME}', '{$HOSTNAME}', '{$TIMESTAMP}'], [ - pathinfo($this->config['database'], PATHINFO_FILENAME), + pathinfo($config['database'], PATHINFO_FILENAME), date('YmdHis'), - str_replace(['127.0.0.1', '::1'], 'localhost', $this->config['host'] ?? 'localhost'), + str_replace(['127.0.0.1', '::1'], 'localhost', $config['host'] ?? 'localhost'), time(), ], $filename); From 7496dab1840bb471fe775b16489baa3c6b8ff968 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sun, 4 Jun 2023 08:40:35 +0200 Subject: [PATCH 15/52] removed `$Driver` public property for `BackupExport`/`BackupImport` and added `AbstractBackupUtility::getDriver()` method --- CHANGELOG.md | 1 + src/Utility/AbstractBackupUtility.php | 30 +++++++++------------ src/Utility/BackupExport.php | 9 +++---- src/Utility/BackupImport.php | 7 +++-- tests/TestCase/Utility/BackupExportTest.php | 22 +++++++-------- tests/TestCase/Utility/BackupImportTest.php | 22 +++++++-------- 6 files changed, 39 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15834660..7a32fa07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ implemented by the driver classes) are directly dispatched by the `BackupExport::export()` and `BackupImport::import()` methods, and no longer by the drivers themselves; * added the `AbstractBackupUtility` abstract class that provides the code common to `BackupExport` and `BackupImport`; +* removed `$Driver` public property for `BackupExport`/`BackupImport` and added `AbstractBackupUtility::getDriver()` method; * `Driver::_exec()` method has become `AbstractBackupUtility::getProcess()`; * `BackupTrait::getDriver()` method has become `AbstractBackupUtility::getDriver()`; * the `BackupExport::export()` and `BackupImport::import()` methods can return the filename path on success or `false` diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index 8e7b249e..5fb00667 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -39,26 +39,16 @@ abstract class AbstractBackupUtility protected string $filename; /** - * Driver containing all methods to export/import database backups according to the connection * @var \DatabaseBackup\Driver\Driver */ - public Driver $Driver; - - /** - * Construct - * @throws \ErrorException|\ReflectionException - */ - public function __construct() - { - $this->Driver = $this->getDriver(); - } + protected Driver $Driver; /** * Sets the filename * @param string $filename Filename. It can be an absolute path * @return $this */ - abstract function filename(string $filename); + public abstract function filename(string $filename); /** * Gets the `Driver` instance, containing all methods to export/import database backups. @@ -71,13 +61,17 @@ abstract function filename(string $filename); */ public function getDriver(?ConnectionInterface $connection = null): Driver { - $connection = $connection ?: $this->getConnection(); - $name = $this->getDriverName($connection); - /** @var class-string<\DatabaseBackup\Driver\Driver> $Driver */ - $Driver = App::classname('DatabaseBackup.' . $name, 'Driver'); - Exceptionist::isTrue($Driver, __d('database_backup', 'The `{0}` driver does not exist', $name)); + if (empty($this->Driver)) { + $connection = $connection ?: $this->getConnection(); + $name = $this->getDriverName($connection); + /** @var class-string<\DatabaseBackup\Driver\Driver> $Driver */ + $Driver = App::classname('DatabaseBackup.' . $name, 'Driver'); + Exceptionist::isTrue($Driver, __d('database_backup', 'The `{0}` driver does not exist', $name)); + + $this->Driver = new $Driver($connection); + } - return new $Driver($connection); + return $this->Driver; } /** diff --git a/src/Utility/BackupExport.php b/src/Utility/BackupExport.php index 5077b0f7..893a887a 100644 --- a/src/Utility/BackupExport.php +++ b/src/Utility/BackupExport.php @@ -61,12 +61,9 @@ class BackupExport extends AbstractBackupUtility /** * Construct - * @throws \ErrorException|\ReflectionException */ public function __construct() { - parent::__construct(); - $this->BackupManager = new BackupManager(); } @@ -182,18 +179,18 @@ public function export() unset($this->filename); //Dispatches the `Backup.beforeExport` event implemented by the driver - $BeforeExport = $this->Driver->dispatchEvent('Backup.beforeExport'); + $BeforeExport = $this->getDriver()->dispatchEvent('Backup.beforeExport'); if ($BeforeExport->isStopped()) { return false; } //Exports - $Process = $this->getProcess($this->Driver->_getExportExecutable($filename)); + $Process = $this->getProcess($this->getDriver()->_getExportExecutable($filename)); Exceptionist::isTrue($Process->isSuccessful(), __d('database_backup', 'Export failed with error message: `{0}`', rtrim($Process->getErrorOutput()))); Filesystem::instance()->chmod($filename, Configure::read('DatabaseBackup.chmod')); //Dispatches the `Backup.afterExport` event implemented by the driver - $this->Driver->dispatchEvent('Backup.afterExport'); + $this->getDriver()->dispatchEvent('Backup.afterExport'); if ($this->emailRecipient) { $this->BackupManager->send($filename, $this->emailRecipient); diff --git a/src/Utility/BackupImport.php b/src/Utility/BackupImport.php index 6530f78f..985d087d 100644 --- a/src/Utility/BackupImport.php +++ b/src/Utility/BackupImport.php @@ -22,7 +22,6 @@ */ class BackupImport extends AbstractBackupUtility { - /** * Sets the filename * @param string $filename Filename. It can be an absolute path @@ -64,17 +63,17 @@ public function import() unset($this->filename); //Dispatches the `Backup.beforeImport` event implemented by the driver - $BeforeImport = $this->Driver->dispatchEvent('Backup.beforeImport'); + $BeforeImport = $this->getDriver()->dispatchEvent('Backup.beforeImport'); if ($BeforeImport->isStopped()) { return false; } //Imports - $Process = $this->getProcess($this->Driver->_getImportExecutable($filename)); + $Process = $this->getProcess($this->getDriver()->_getImportExecutable($filename)); Exceptionist::isTrue($Process->isSuccessful(), __d('database_backup', 'Import failed with error message: `{0}`', rtrim($Process->getErrorOutput()))); //Dispatches the `Backup.afterImport` event implemented by the driver - $this->Driver->dispatchEvent('Backup.afterImport'); + $this->getDriver()->dispatchEvent('Backup.afterImport'); return $filename; } diff --git a/tests/TestCase/Utility/BackupExportTest.php b/tests/TestCase/Utility/BackupExportTest.php index c52f653e..f807ed21 100644 --- a/tests/TestCase/Utility/BackupExportTest.php +++ b/tests/TestCase/Utility/BackupExportTest.php @@ -46,7 +46,7 @@ public function setUp(): void parent::setUp(); $this->BackupExport ??= new BackupExport(); - $this->BackupExport->Driver->getEventManager()->setEventList(new EventList()); + $this->BackupExport->getDriver()->getEventManager()->setEventList(new EventList()); } /** @@ -140,8 +140,8 @@ public function testExport(): void $file = $this->BackupExport->export() ?: ''; $this->assertFileExists($file); $this->assertMatchesRegularExpression('/^backup_test_\d{14}\.sql$/', basename($file)); - $this->assertEventFired('Backup.beforeExport', $this->BackupExport->Driver->getEventManager()); - $this->assertEventFired('Backup.afterExport', $this->BackupExport->Driver->getEventManager()); + $this->assertEventFired('Backup.beforeExport', $this->BackupExport->getDriver()->getEventManager()); + $this->assertEventFired('Backup.afterExport', $this->BackupExport->getDriver()->getEventManager()); //Exports with `compression()` $file = $this->BackupExport->compression('bzip2')->export() ?: ''; @@ -189,9 +189,11 @@ public function testExportWithDifferentChmod(): void */ public function testExportStoppedByBeforeExport(): void { - $this->BackupExport->Driver = $this->getMockForAbstractDriver(['beforeExport']); - $this->BackupExport->Driver->method('beforeExport')->willReturn(false); - $this->assertFalse($this->BackupExport->export()); + $Driver = $this->getMockForAbstractDriver(['beforeExport']); + $Driver->method('beforeExport')->willReturn(false); + $BackupExport = $this->createPartialMock(BackupExport::class, ['getDriver']); + $BackupExport->method('getDriver')->willReturn($Driver); + $this->assertFalse($BackupExport->export()); } /** @@ -204,9 +206,7 @@ public function testExportOnFailure(): void $expectedError = 'mysqldump: Got error: 1044: "Access denied for user \'root\'@\'localhost\' to database \'noExisting\'" when selecting the database'; $this->expectExceptionMessage('Export failed with error message: `' . $expectedError . '`'); $Process = $this->createConfiguredMock(Process::class, ['getErrorOutput' => $expectedError . PHP_EOL, 'isSuccessful' => false]); - $BackupExport = $this->getMockBuilder(BackupExport::class) - ->onlyMethods(['getProcess']) - ->getMock(); + $BackupExport = $this->createPartialMock(BackupExport::class, ['getProcess']); $BackupExport->method('getProcess')->willReturn($Process); $BackupExport->export(); } @@ -222,9 +222,7 @@ public function testExportExceedingTimeout(): void $this->expectException(ProcessTimedOutException::class); $this->expectExceptionMessage('The process "dir" exceeded the timeout of 60 seconds'); $ProcessTimedOutException = new ProcessTimedOutException(Process::fromShellCommandline('dir'), 1); - $BackupExport = $this->getMockBuilder(BackupExport::class) - ->onlyMethods(['getProcess']) - ->getMock(); + $BackupExport = $this->createPartialMock(BackupExport::class, ['getProcess']); $BackupExport->method('getProcess')->willThrowException($ProcessTimedOutException); $BackupExport->export(); } diff --git a/tests/TestCase/Utility/BackupImportTest.php b/tests/TestCase/Utility/BackupImportTest.php index 7bfe8329..f8162ecd 100644 --- a/tests/TestCase/Utility/BackupImportTest.php +++ b/tests/TestCase/Utility/BackupImportTest.php @@ -45,7 +45,7 @@ public function setUp(): void parent::setUp(); $this->BackupImport ??= new BackupImport(); - $this->BackupImport->Driver->getEventManager()->setEventList(new EventList()); + $this->BackupImport->getDriver()->getEventManager()->setEventList(new EventList()); } /** @@ -87,8 +87,8 @@ public function testImport(): void $result = $this->BackupImport->filename($expectedFilename)->import() ?: ''; $this->assertStringEndsWith('backup.' . $extension, $result); $this->assertSame($expectedFilename, $result); - $this->assertEventFired('Backup.beforeImport', $this->BackupImport->Driver->getEventManager()); - $this->assertEventFired('Backup.afterImport', $this->BackupImport->Driver->getEventManager()); + $this->assertEventFired('Backup.beforeImport', $this->BackupImport->getDriver()->getEventManager()); + $this->assertEventFired('Backup.afterImport', $this->BackupImport->getDriver()->getEventManager()); } $this->expectExceptionMessage('You must first set the filename'); @@ -102,9 +102,11 @@ public function testImport(): void */ public function testImportStoppedByBeforeExport(): void { - $this->BackupImport->Driver = $this->getMockForAbstractDriver(['beforeImport']); - $this->BackupImport->Driver->method('beforeImport')->willReturn(false); - $this->assertFalse($this->BackupImport->filename(createBackup())->import()); + $Driver = $this->getMockForAbstractDriver(['beforeImport']); + $Driver->method('beforeImport')->willReturn(false); + $BackupImport = $this->createPartialMock(BackupImport::class, ['getDriver']); + $BackupImport->method('getDriver')->willReturn($Driver); + $this->assertFalse($BackupImport->filename(createBackup())->import()); } /** @@ -117,9 +119,7 @@ public function testImportOnFailure(): void $expectedError = 'ERROR 1044 (42000): Access denied for user \'root\'@\'localhost\' to database \'noExisting\''; $this->expectExceptionMessage('Import failed with error message: `' . $expectedError . '`'); $Process = $this->createConfiguredMock(Process::class, ['getErrorOutput' => $expectedError . PHP_EOL, 'isSuccessful' => false]); - $BackupImport = $this->getMockBuilder(BackupImport::class) - ->onlyMethods(['getProcess']) - ->getMock(); + $BackupImport = $this->createPartialMock(BackupImport::class, ['getProcess']); $BackupImport->method('getProcess')->willReturn($Process); $BackupImport->filename(createBackup())->import(); } @@ -135,9 +135,7 @@ public function testImportExceedingTimeout(): void $this->expectException(ProcessTimedOutException::class); $this->expectExceptionMessage('The process "dir" exceeded the timeout of 60 seconds'); $ProcessTimedOutException = new ProcessTimedOutException(Process::fromShellCommandline('dir'), 1); - $BackupImport = $this->getMockBuilder(BackupImport::class) - ->onlyMethods(['getProcess']) - ->getMock(); + $BackupImport = $this->createPartialMock(BackupImport::class, ['getProcess']); $BackupImport->method('getProcess')->willThrowException($ProcessTimedOutException); $BackupImport->filename(createBackup())->import(); } From 233301db24315dae0e8b3cd1d17dfc851b9c3e7c Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sun, 4 Jun 2023 08:57:54 +0200 Subject: [PATCH 16/52] fixed visibility --- src/Utility/AbstractBackupUtility.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index 5fb00667..1855e5ff 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -48,7 +48,7 @@ abstract class AbstractBackupUtility * @param string $filename Filename. It can be an absolute path * @return $this */ - public abstract function filename(string $filename); + abstract public function filename(string $filename); /** * Gets the `Driver` instance, containing all methods to export/import database backups. From 52b6dba358be173cd90b59866e21309d16e82786 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sun, 4 Jun 2023 09:13:19 +0200 Subject: [PATCH 17/52] `Driver::_getExecutable()`, `Driver::_getExportExecutable()` and `Driver::_getImportExecutable()` have become `Driver::getExecutable()`, `Driver::getExportExecutable()` and `Driver::getImportExecutable()` --- CHANGELOG.md | 2 ++ src/Driver/Driver.php | 10 +++++----- src/TestSuite/DriverTestCase.php | 16 ++++++---------- src/Utility/BackupExport.php | 2 +- src/Utility/BackupImport.php | 2 +- tests/TestCase/Driver/MysqlTest.php | 3 +++ 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a32fa07..e36d50f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ * `BackupTrait::getDriver()` method has become `AbstractBackupUtility::getDriver()`; * the `BackupExport::export()` and `BackupImport::import()` methods can return the filename path on success or `false` if the `Backup.beforeExport`/`Backup.beforeImport` events are stopped; +* `Driver::_getExecutable()`, `Driver::_getExportExecutable()` and `Driver::_getImportExecutable()` have become + `Driver::getExecutable()`, `Driver::getExportExecutable()` and `Driver::getImportExecutable()`; * the code of `Driver::export()` and `Driver::import()` methods has been absorbed by `BackupExport::export()` and `BackupImport::import()` and therefore those methods no longer exist; * removed useless `BackupExport::$config` property; diff --git a/src/Driver/Driver.php b/src/Driver/Driver.php index 7a1656a4..fb14a046 100644 --- a/src/Driver/Driver.php +++ b/src/Driver/Driver.php @@ -77,7 +77,7 @@ final public function implementedEvents(): array * @throws \ReflectionException * @throws \ErrorException */ - protected function _getExecutable(string $type): string + protected function getExecutable(string $type): string { Exceptionist::inArray($type, ['export', 'import']); $driver = strtolower(self::getDriverName()); @@ -102,9 +102,9 @@ protected function _getExecutable(string $type): string * @throws \ReflectionException * @throws \ErrorException */ - public function _getExportExecutable(string $filename): string + public function getExportExecutable(string $filename): string { - $exec = $this->_getExecutable('export'); + $exec = $this->getExecutable('export'); $compression = self::getCompression($filename); if ($compression) { $exec .= ' | ' . escapeshellarg($this->getBinary($compression)); @@ -121,9 +121,9 @@ public function _getExportExecutable(string $filename): string * @throws \ReflectionException * @throws \ErrorException */ - public function _getImportExecutable(string $filename): string + public function getImportExecutable(string $filename): string { - $exec = $this->_getExecutable('import'); + $exec = $this->getExecutable('import'); $compression = self::getCompression($filename); if ($compression) { return sprintf('%s -dc %s | ', escapeshellarg($this->getBinary($compression)), escapeshellarg($filename)) . $exec; diff --git a/src/TestSuite/DriverTestCase.php b/src/TestSuite/DriverTestCase.php index cbff5b15..f83b6312 100644 --- a/src/TestSuite/DriverTestCase.php +++ b/src/TestSuite/DriverTestCase.php @@ -17,7 +17,6 @@ namespace DatabaseBackup\TestSuite; use DatabaseBackup\Driver\Driver; -use Tools\TestSuite\ReflectionTrait; /** * DriverTestCase class. @@ -26,14 +25,11 @@ */ abstract class DriverTestCase extends TestCase { - use ReflectionTrait; - /** * @var \DatabaseBackup\Driver\Driver */ protected Driver $Driver; - /** * Called before every test method * @return void @@ -55,15 +51,15 @@ public function setUp(): void /** * @return void * @throws \ReflectionException|\ErrorException - * @uses \DatabaseBackup\Driver\Driver::_getExportExecutable() + * @uses \DatabaseBackup\Driver\Driver::getExportExecutable() */ public function testGetExportExecutable(): void { - $this->assertNotEmpty($this->invokeMethod($this->Driver, '_getExportExecutable', ['backup.sql'])); + $this->assertNotEmpty($this->Driver->getExportExecutable('backup.sql')); //Gzip and Bzip2 compressions foreach (['gzip' => 'backup.sql.gz', 'bzip2' => 'backup.sql.bz2'] as $compression => $filename) { - $result = $this->invokeMethod($this->Driver, '_getExportExecutable', [$filename]); + $result = $this->Driver->getExportExecutable($filename); $expected = sprintf(' | %s > %s', escapeshellarg($this->Driver->getBinary($compression)), escapeshellarg($filename)); $this->assertStringEndsWith($expected, $result); } @@ -72,15 +68,15 @@ public function testGetExportExecutable(): void /** * @return void * @throws \ReflectionException|\ErrorException - * @uses \DatabaseBackup\Driver\Driver::_getImportExecutable() + * @uses \DatabaseBackup\Driver\Driver::getImportExecutable() */ public function testGetImportExecutable(): void { - $this->assertNotEmpty($this->invokeMethod($this->Driver, '_getImportExecutable', ['backup.sql'])); + $this->assertNotEmpty($this->Driver->getImportExecutable('backup.sql')); //Gzip and Bzip2 compressions foreach (['gzip' => 'backup.sql.gz', 'bzip2' => 'backup.sql.bz2'] as $compression => $filename) { - $result = $this->invokeMethod($this->Driver, '_getImportExecutable', [$filename]); + $result = $this->Driver->getImportExecutable($filename); $expected = sprintf('%s -dc %s | ', escapeshellarg($this->Driver->getBinary($compression)), escapeshellarg($filename)); $this->assertStringStartsWith($expected, $result); } diff --git a/src/Utility/BackupExport.php b/src/Utility/BackupExport.php index 893a887a..610b66b9 100644 --- a/src/Utility/BackupExport.php +++ b/src/Utility/BackupExport.php @@ -185,7 +185,7 @@ public function export() } //Exports - $Process = $this->getProcess($this->getDriver()->_getExportExecutable($filename)); + $Process = $this->getProcess($this->getDriver()->getExportExecutable($filename)); Exceptionist::isTrue($Process->isSuccessful(), __d('database_backup', 'Export failed with error message: `{0}`', rtrim($Process->getErrorOutput()))); Filesystem::instance()->chmod($filename, Configure::read('DatabaseBackup.chmod')); diff --git a/src/Utility/BackupImport.php b/src/Utility/BackupImport.php index 985d087d..5ff9959b 100644 --- a/src/Utility/BackupImport.php +++ b/src/Utility/BackupImport.php @@ -69,7 +69,7 @@ public function import() } //Imports - $Process = $this->getProcess($this->getDriver()->_getImportExecutable($filename)); + $Process = $this->getProcess($this->getDriver()->getImportExecutable($filename)); Exceptionist::isTrue($Process->isSuccessful(), __d('database_backup', 'Import failed with error message: `{0}`', rtrim($Process->getErrorOutput()))); //Dispatches the `Backup.afterImport` event implemented by the driver diff --git a/tests/TestCase/Driver/MysqlTest.php b/tests/TestCase/Driver/MysqlTest.php index 23bcb9b3..1d52c341 100644 --- a/tests/TestCase/Driver/MysqlTest.php +++ b/tests/TestCase/Driver/MysqlTest.php @@ -17,12 +17,15 @@ use DatabaseBackup\Driver\Mysql; use DatabaseBackup\TestSuite\DriverTestCase; +use Tools\ReflectionTrait; /** * MysqlTest class */ class MysqlTest extends DriverTestCase { + use ReflectionTrait; + /** * Called before every test method * @return void From da24e29f127a4eba979e3e8951ba66dc9d1a9729 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sun, 4 Jun 2023 10:21:49 +0200 Subject: [PATCH 18/52] fixed code --- src/TestSuite/DriverTestCase.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/TestSuite/DriverTestCase.php b/src/TestSuite/DriverTestCase.php index f83b6312..e232206b 100644 --- a/src/TestSuite/DriverTestCase.php +++ b/src/TestSuite/DriverTestCase.php @@ -16,6 +16,7 @@ */ namespace DatabaseBackup\TestSuite; +use Cake\Core\App; use DatabaseBackup\Driver\Driver; /** @@ -38,12 +39,12 @@ public function setUp(): void { parent::setUp(); - /** @var \Cake\Database\Connection $connection */ - $connection = $this->getConnection('test'); + if (empty($this->Driver)) { + /** @var \Cake\Database\Connection $connection */ + $connection = $this->getConnection('test'); - if (empty($this->DriverClass) || empty($this->Driver)) { /** @var class-string<\DatabaseBackup\Driver\Driver> $DriverClass */ - $DriverClass = 'DatabaseBackup\\Driver\\' . get_class_short_name($connection->config()['driver']); + $DriverClass = App::className('DatabaseBackup.' . get_class_short_name($connection->config()['driver']), 'Driver'); $this->Driver = new $DriverClass($connection); } } @@ -58,7 +59,8 @@ public function testGetExportExecutable(): void $this->assertNotEmpty($this->Driver->getExportExecutable('backup.sql')); //Gzip and Bzip2 compressions - foreach (['gzip' => 'backup.sql.gz', 'bzip2' => 'backup.sql.bz2'] as $compression => $filename) { + foreach (array_flip(array_filter(DATABASE_BACKUP_EXTENSIONS)) as $compression => $extension) { + $filename = 'backup.' . $extension; $result = $this->Driver->getExportExecutable($filename); $expected = sprintf(' | %s > %s', escapeshellarg($this->Driver->getBinary($compression)), escapeshellarg($filename)); $this->assertStringEndsWith($expected, $result); @@ -75,7 +77,8 @@ public function testGetImportExecutable(): void $this->assertNotEmpty($this->Driver->getImportExecutable('backup.sql')); //Gzip and Bzip2 compressions - foreach (['gzip' => 'backup.sql.gz', 'bzip2' => 'backup.sql.bz2'] as $compression => $filename) { + foreach (array_flip(array_filter(DATABASE_BACKUP_EXTENSIONS)) as $compression => $extension) { + $filename = 'backup.' . $extension; $result = $this->Driver->getImportExecutable($filename); $expected = sprintf('%s -dc %s | ', escapeshellarg($this->Driver->getBinary($compression)), escapeshellarg($filename)); $this->assertStringStartsWith($expected, $result); From e3e303ce3f87cf58a388fb3be547ca0efb37c805 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sun, 4 Jun 2023 10:48:27 +0200 Subject: [PATCH 19/52] MySql::deleteAuthFile()` method returns void (there is no need for it to return anything) --- CHANGELOG.md | 1 + src/Driver/Mysql.php | 13 +++++-------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e36d50f3..df9f4c40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ `Driver::getExecutable()`, `Driver::getExportExecutable()` and `Driver::getImportExecutable()`; * the code of `Driver::export()` and `Driver::import()` methods has been absorbed by `BackupExport::export()` and `BackupImport::import()` and therefore those methods no longer exist; +* `MySql::deleteAuthFile()` method returns void (there is no need for it to return anything); * removed useless `BackupExport::$config` property; * completely improved the `BackupImportTest` tests. diff --git a/src/Driver/Mysql.php b/src/Driver/Mysql.php index 94c07d2e..3b2ad5c4 100644 --- a/src/Driver/Mysql.php +++ b/src/Driver/Mysql.php @@ -121,20 +121,17 @@ public function beforeImport(): bool /** * Deletes the temporary file with the database authentication data - * @return bool `true` on success + * @return void * @since 2.1.0 */ - protected function deleteAuthFile(): bool + protected function deleteAuthFile(): void { $authFile = $this->getAuthFile(); - if (!$authFile) { - return false; + if ($authFile) { + //Deletes the temporary file with the authentication data + Filesystem::instance()->remove($authFile); } - //Deletes the temporary file with the authentication data - Filesystem::instance()->remove($authFile); unset($this->auth); - - return true; } } From 2f867a832f822686f1364350435057325eaf53fd Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sun, 4 Jun 2023 11:37:29 +0200 Subject: [PATCH 20/52] fixed code and tests --- src/Driver/Mysql.php | 23 ++---- tests/TestCase/Driver/MysqlTest.php | 107 ++++++++++++++++++---------- 2 files changed, 78 insertions(+), 52 deletions(-) diff --git a/src/Driver/Mysql.php b/src/Driver/Mysql.php index 3b2ad5c4..5a4f96dc 100644 --- a/src/Driver/Mysql.php +++ b/src/Driver/Mysql.php @@ -23,27 +23,27 @@ class Mysql extends Driver { /** - * Temporary file with the database authentication data * @since 2.1.0 * @var string */ - private string $auth = ''; + private string $auth; /** - * Internal method to get the auth file + * Internal method to get the auth file path. + * + * This method returns only the path that will be used and does not verify that the file already exists. * @return string * @since 2.11.0 */ protected function getAuthFile(): string { - return $this->auth && file_exists($this->auth) ? $this->auth : ''; + return $this->auth ??= TMP . uniqid('auth'); } /** * Internal method to write an auth file * @param string $content Content * @return bool - * @throws \ErrorException * @since 2.3.0 */ protected function writeAuthFile(string $content): bool @@ -54,9 +54,7 @@ protected function writeAuthFile(string $content): bool $content ); - $this->auth = Filesystem::createTmpFile($content, null, 'auth'); - - return $this->auth != false; + return (bool)Filesystem::createFile($this->getAuthFile(), $content); } /** @@ -88,7 +86,6 @@ public function afterImport(): void * user can execute a `ps aux | grep mysqldump` and see the password). * So it creates a temporary file to store the configuration options. * @return bool - * @throws \ErrorException * @since 2.1.0 */ public function beforeExport(): bool @@ -108,7 +105,6 @@ public function beforeExport(): bool * user can execute a `ps aux | grep mysqldump` and see the password). * So it creates a temporary file to store the configuration options. * @return bool - * @throws \ErrorException * @since 2.1.0 */ public function beforeImport(): bool @@ -126,12 +122,7 @@ public function beforeImport(): bool */ protected function deleteAuthFile(): void { - $authFile = $this->getAuthFile(); - if ($authFile) { - //Deletes the temporary file with the authentication data - Filesystem::instance()->remove($authFile); - } - + Filesystem::instance()->remove($this->getAuthFile()); unset($this->auth); } } diff --git a/tests/TestCase/Driver/MysqlTest.php b/tests/TestCase/Driver/MysqlTest.php index 1d52c341..bea44fb7 100644 --- a/tests/TestCase/Driver/MysqlTest.php +++ b/tests/TestCase/Driver/MysqlTest.php @@ -15,16 +15,20 @@ */ namespace DatabaseBackup\Test\TestCase\Driver; +use DatabaseBackup\Driver\Driver; use DatabaseBackup\Driver\Mysql; use DatabaseBackup\TestSuite\DriverTestCase; -use Tools\ReflectionTrait; +use Tools\Filesystem; /** * MysqlTest class */ class MysqlTest extends DriverTestCase { - use ReflectionTrait; + /** + * @var \DatabaseBackup\Driver\Mysql&\PHPUnit\Framework\MockObject\MockObject + */ + protected Driver $Driver; /** * Called before every test method @@ -32,11 +36,18 @@ class MysqlTest extends DriverTestCase */ public function setUp(): void { - parent::setUp(); + $connection = $this->getConnection('test'); - if (!$this->Driver instanceof Mysql) { + if (get_class_short_name($connection->getDriver()) !== 'Mysql') { $this->markTestSkipped('Skipping tests for Mysql, current driver is ' . $this->Driver->getDriverName()); } + + $this->Driver ??= $this->getMockBuilder(Mysql::class) + ->setConstructorArgs([$this->getConnection('test')]) + ->onlyMethods(['getAuthFile', 'deleteAuthFile', 'writeAuthFile']) + ->getMock(); + + parent::setUp(); } /** @@ -45,9 +56,16 @@ public function setUp(): void */ public function testAfterExport(): void { - $Driver = $this->createPartialMock(Mysql::class, ['deleteAuthFile']); - $Driver->expects($this->once())->method('deleteAuthFile'); - $Driver->afterExport(); + $expectedAuthFile = Filesystem::createTmpFile(); + $this->assertFileExists($expectedAuthFile); + + $Driver = $this->getMockBuilder(Mysql::class) + ->setConstructorArgs([$this->getConnection('test')]) + ->onlyMethods(['getAuthFile']) + ->getMock(); + $Driver->method('getAuthFile')->willReturn($expectedAuthFile); + $Driver->dispatchEvent('Backup.afterExport'); + $this->assertFileDoesNotExist($expectedAuthFile); } /** @@ -56,9 +74,16 @@ public function testAfterExport(): void */ public function testAfterImport(): void { - $Driver = $this->createPartialMock(Mysql::class, ['deleteAuthFile']); - $Driver->expects($this->once())->method('deleteAuthFile'); - $Driver->afterImport(); + $expectedAuthFile = Filesystem::createTmpFile(); + $this->assertFileExists($expectedAuthFile); + + $Driver = $this->getMockBuilder(Mysql::class) + ->setConstructorArgs([$this->getConnection('test')]) + ->onlyMethods(['getAuthFile']) + ->getMock(); + $Driver->method('getAuthFile')->willReturn($expectedAuthFile); + $Driver->dispatchEvent('Backup.afterImport'); + $this->assertFileDoesNotExist($expectedAuthFile); } /** @@ -67,16 +92,17 @@ public function testAfterImport(): void */ public function testBeforeExport(): void { - $this->assertTrue($this->Driver->beforeExport()); + $expectedContent = '[mysqldump]' . PHP_EOL . + 'user={{USER}}' . PHP_EOL . + 'password="{{PASSWORD}}"' . PHP_EOL . + 'host={{HOST}}'; - $expected = '[mysqldump]' . PHP_EOL . - 'user=' . $this->Driver->getConfig('username') . PHP_EOL . - 'password="' . $this->Driver->getConfig('password') . '"' . PHP_EOL . - 'host=' . $this->Driver->getConfig('host'); - $auth = $this->invokeMethod($this->Driver, 'getAuthFile'); - $this->assertStringEqualsFile($auth, $expected); + $this->Driver->expects($this->once()) + ->method('writeAuthFile') + ->with($this->equalTo($expectedContent)) + ->willReturn(true); - unlink($auth); + $this->assertTrue($this->Driver->dispatchEvent('Backup.beforeExport')->getResult()); } /** @@ -85,31 +111,40 @@ public function testBeforeExport(): void */ public function testBeforeImport(): void { - $this->assertTrue($this->Driver->beforeImport()); + $expectedContent = '[client]' . PHP_EOL . + 'user={{USER}}' . PHP_EOL . + 'password="{{PASSWORD}}"' . PHP_EOL . + 'host={{HOST}}'; - $expected = '[client]' . PHP_EOL . - 'user=' . $this->Driver->getConfig('username') . PHP_EOL . - 'password="' . $this->Driver->getConfig('password') . '"' . PHP_EOL . - 'host=' . $this->Driver->getConfig('host'); - $auth = $this->invokeMethod($this->Driver, 'getAuthFile'); - $this->assertStringEqualsFile($auth, $expected); + $this->Driver->expects($this->once()) + ->method('writeAuthFile') + ->with($this->equalTo($expectedContent)) + ->willReturn(true); - unlink($auth); + $this->assertTrue($this->Driver->dispatchEvent('Backup.beforeImport')->getResult()); } /** * @test - * @uses \DatabaseBackup\Driver\Mysql::deleteAuthFile() + * @uses \DatabaseBackup\Driver\Mysql::writeAuthFile() */ - public function testDeleteAuthFile(): void + public function testWriteAuthFile(): void { - $this->assertFalse($this->invokeMethod($this->Driver, 'deleteAuthFile')); - - $auth = tempnam(sys_get_temp_dir(), 'auth') ?: ''; - $Driver = $this->createPartialMock(Mysql::class, ['getAuthFile']); - $Driver->method('getAuthFile')->willReturn($auth); - $this->assertFileExists($auth); - $this->assertTrue($this->invokeMethod($Driver, 'deleteAuthFile')); - $this->assertFileDoesNotExist($auth); + $expectedAuthFile = TMP . 'auth' . uniqid(); + $this->assertFileDoesNotExist($expectedAuthFile); + + $Driver = $this->getMockBuilder(Mysql::class) + ->setConstructorArgs([$this->getConnection('test')]) + ->onlyMethods(['getAuthFile']) + ->getMock(); + $Driver->method('getAuthFile')->willReturn($expectedAuthFile); + + //Dispatches an event that calls and returns `writeAuthFile()` + $this->assertTrue($Driver->dispatchEvent('Backup.beforeExport')->getResult()); + $this->assertFileExists($expectedAuthFile); + $this->assertSame('[mysqldump]' . PHP_EOL . + 'user=travis' . PHP_EOL . + 'password=""' . PHP_EOL . + 'host=localhost', file_get_contents($expectedAuthFile)); } } From f44a6310b0c5ff5575d161791a6f530c6c65ec92 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Sun, 4 Jun 2023 11:39:20 +0200 Subject: [PATCH 21/52] `MySql::getAuthFile()` method has become `getAuthFilePath()`, so as to be more understandable --- CHANGELOG.md | 1 + src/Driver/Driver.php | 2 +- src/Driver/Mysql.php | 6 +++--- tests/TestCase/Driver/MysqlTest.php | 14 +++++++------- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index df9f4c40..3a7bd5cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ `Driver::getExecutable()`, `Driver::getExportExecutable()` and `Driver::getImportExecutable()`; * the code of `Driver::export()` and `Driver::import()` methods has been absorbed by `BackupExport::export()` and `BackupImport::import()` and therefore those methods no longer exist; +* `MySql::getAuthFile()` method has become `getAuthFilePath()`, so as to be more understandable; * `MySql::deleteAuthFile()` method returns void (there is no need for it to return anything); * removed useless `BackupExport::$config` property; * completely improved the `BackupImportTest` tests. diff --git a/src/Driver/Driver.php b/src/Driver/Driver.php index fb14a046..2c9913ed 100644 --- a/src/Driver/Driver.php +++ b/src/Driver/Driver.php @@ -83,7 +83,7 @@ protected function getExecutable(string $type): string $driver = strtolower(self::getDriverName()); $replacements = [ '{{BINARY}}' => escapeshellarg($this->getBinary(DATABASE_BACKUP_EXECUTABLES[$driver][$type])), - '{{AUTH_FILE}}' => method_exists($this, 'getAuthFile') && $this->getAuthFile() ? escapeshellarg($this->getAuthFile()) : '', + '{{AUTH_FILE}}' => method_exists($this, 'getAuthFile') && $this->getAuthFilePath() ? escapeshellarg($this->getAuthFilePath()) : '', '{{DB_USER}}' => $this->getConfig('username'), '{{DB_PASSWORD}}' => $this->getConfig('password') ? ':' . $this->getConfig('password') : '', '{{DB_HOST}}' => $this->getConfig('host'), diff --git a/src/Driver/Mysql.php b/src/Driver/Mysql.php index 5a4f96dc..9f4ffa1d 100644 --- a/src/Driver/Mysql.php +++ b/src/Driver/Mysql.php @@ -35,7 +35,7 @@ class Mysql extends Driver * @return string * @since 2.11.0 */ - protected function getAuthFile(): string + protected function getAuthFilePath(): string { return $this->auth ??= TMP . uniqid('auth'); } @@ -54,7 +54,7 @@ protected function writeAuthFile(string $content): bool $content ); - return (bool)Filesystem::createFile($this->getAuthFile(), $content); + return (bool)Filesystem::createFile($this->getAuthFilePath(), $content); } /** @@ -122,7 +122,7 @@ public function beforeImport(): bool */ protected function deleteAuthFile(): void { - Filesystem::instance()->remove($this->getAuthFile()); + Filesystem::instance()->remove($this->getAuthFilePath()); unset($this->auth); } } diff --git a/tests/TestCase/Driver/MysqlTest.php b/tests/TestCase/Driver/MysqlTest.php index bea44fb7..599ab46c 100644 --- a/tests/TestCase/Driver/MysqlTest.php +++ b/tests/TestCase/Driver/MysqlTest.php @@ -44,7 +44,7 @@ public function setUp(): void $this->Driver ??= $this->getMockBuilder(Mysql::class) ->setConstructorArgs([$this->getConnection('test')]) - ->onlyMethods(['getAuthFile', 'deleteAuthFile', 'writeAuthFile']) + ->onlyMethods(['getAuthFilePath', 'deleteAuthFile', 'writeAuthFile']) ->getMock(); parent::setUp(); @@ -61,9 +61,9 @@ public function testAfterExport(): void $Driver = $this->getMockBuilder(Mysql::class) ->setConstructorArgs([$this->getConnection('test')]) - ->onlyMethods(['getAuthFile']) + ->onlyMethods(['getAuthFilePath']) ->getMock(); - $Driver->method('getAuthFile')->willReturn($expectedAuthFile); + $Driver->method('getAuthFilePath')->willReturn($expectedAuthFile); $Driver->dispatchEvent('Backup.afterExport'); $this->assertFileDoesNotExist($expectedAuthFile); } @@ -79,9 +79,9 @@ public function testAfterImport(): void $Driver = $this->getMockBuilder(Mysql::class) ->setConstructorArgs([$this->getConnection('test')]) - ->onlyMethods(['getAuthFile']) + ->onlyMethods(['getAuthFilePath']) ->getMock(); - $Driver->method('getAuthFile')->willReturn($expectedAuthFile); + $Driver->method('getAuthFilePath')->willReturn($expectedAuthFile); $Driver->dispatchEvent('Backup.afterImport'); $this->assertFileDoesNotExist($expectedAuthFile); } @@ -135,9 +135,9 @@ public function testWriteAuthFile(): void $Driver = $this->getMockBuilder(Mysql::class) ->setConstructorArgs([$this->getConnection('test')]) - ->onlyMethods(['getAuthFile']) + ->onlyMethods(['getAuthFilePath']) ->getMock(); - $Driver->method('getAuthFile')->willReturn($expectedAuthFile); + $Driver->method('getAuthFilePath')->willReturn($expectedAuthFile); //Dispatches an event that calls and returns `writeAuthFile()` $this->assertTrue($Driver->dispatchEvent('Backup.beforeExport')->getResult()); From 1288cdf3019773daf3b8560a38b7c2ca44d8e9bc Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 14:53:41 +0200 Subject: [PATCH 22/52] the `Driver::getConfig()` method no longer accepts `null` as argument, but only a string as key, since there is no need to return the whole configuration --- CHANGELOG.md | 4 +++- src/Driver/Driver.php | 16 +++++++--------- tests/TestCase/Driver/DriverTest.php | 1 - 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a7bd5cb..55d0806d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,9 +12,11 @@ if the `Backup.beforeExport`/`Backup.beforeImport` events are stopped; * `Driver::_getExecutable()`, `Driver::_getExportExecutable()` and `Driver::_getImportExecutable()` have become `Driver::getExecutable()`, `Driver::getExportExecutable()` and `Driver::getImportExecutable()`; +* the `Driver::getConfig()` method no longer accepts `null` as argument, but only a string as key, since there is no + need to return the whole configuration; * the code of `Driver::export()` and `Driver::import()` methods has been absorbed by `BackupExport::export()` and `BackupImport::import()` and therefore those methods no longer exist; -* `MySql::getAuthFile()` method has become `getAuthFilePath()`, so as to be more understandable; +* `MySql::getAuthFile()` method has become `getAuthFilePath()`, to be more understandable; * `MySql::deleteAuthFile()` method returns void (there is no need for it to return anything); * removed useless `BackupExport::$config` property; * completely improved the `BackupImportTest` tests. diff --git a/src/Driver/Driver.php b/src/Driver/Driver.php index 2c9913ed..81cbae7a 100644 --- a/src/Driver/Driver.php +++ b/src/Driver/Driver.php @@ -69,7 +69,7 @@ final public function implementedEvents(): array * Gets and parses executable commands from the configuration, according to the type of requested operation * (`export` or `import`) and the connection driver. * - * These executables are not yet final, use instead `_getExportExecutable()` and `_getImportExecutable()` methods to + * These executables are not yet final, use instead `getExportExecutable()` and `getImportExecutable()` methods to * have the final executables, including compression. * @param string $type Type or the request operation (`export` or `import`) * @return string @@ -83,7 +83,7 @@ protected function getExecutable(string $type): string $driver = strtolower(self::getDriverName()); $replacements = [ '{{BINARY}}' => escapeshellarg($this->getBinary(DATABASE_BACKUP_EXECUTABLES[$driver][$type])), - '{{AUTH_FILE}}' => method_exists($this, 'getAuthFile') && $this->getAuthFilePath() ? escapeshellarg($this->getAuthFilePath()) : '', + '{{AUTH_FILE}}' => method_exists($this, 'getAuthFilePath') && $this->getAuthFilePath() ? escapeshellarg($this->getAuthFilePath()) : '', '{{DB_USER}}' => $this->getConfig('username'), '{{DB_PASSWORD}}' => $this->getConfig('password') ? ':' . $this->getConfig('password') : '', '{{DB_HOST}}' => $this->getConfig('host'), @@ -182,15 +182,13 @@ final public function getBinary(string $name): string } /** - * Gets a config value or the whole configuration of the connection - * @param string|null $key Config key or `null` to get all config values - * @return mixed Config value, `null` if the key doesn't exist or all config values if no key was specified + * Gets a config value of the connection + * @param string $key Config key + * @return mixed Config value or `null` if the key doesn't exist * @since 2.3.0 */ - final public function getConfig(?string $key = null) + final public function getConfig(string $key) { - $config = $this->connection->config(); - - return $key ? $config[$key] ?? null : $config; + return $this->connection->config()[$key] ?? null; } } diff --git a/tests/TestCase/Driver/DriverTest.php b/tests/TestCase/Driver/DriverTest.php index abc9bdeb..206e72a1 100644 --- a/tests/TestCase/Driver/DriverTest.php +++ b/tests/TestCase/Driver/DriverTest.php @@ -62,7 +62,6 @@ public function testGetBinary(): void */ public function testGetConfig(): void { - $this->assertIsArrayNotEmpty($this->Driver->getConfig()); $this->assertNotEmpty($this->Driver->getConfig('name')); $this->assertNull($this->Driver->getConfig('noExistingKey')); } From 39601649c5126b378f2a5e24b361cafa817efb5d Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 14:55:21 +0200 Subject: [PATCH 23/52] fixed tests --- tests/TestCase/Driver/MysqlTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/TestCase/Driver/MysqlTest.php b/tests/TestCase/Driver/MysqlTest.php index 599ab46c..2595e569 100644 --- a/tests/TestCase/Driver/MysqlTest.php +++ b/tests/TestCase/Driver/MysqlTest.php @@ -36,17 +36,17 @@ class MysqlTest extends DriverTestCase */ public function setUp(): void { + $this->Driver ??= $this->getMockBuilder(Mysql::class) + ->setConstructorArgs([$this->getConnection('test')]) + ->onlyMethods(['getAuthFilePath', 'deleteAuthFile', 'writeAuthFile']) + ->getMock(); + $connection = $this->getConnection('test'); if (get_class_short_name($connection->getDriver()) !== 'Mysql') { $this->markTestSkipped('Skipping tests for Mysql, current driver is ' . $this->Driver->getDriverName()); } - $this->Driver ??= $this->getMockBuilder(Mysql::class) - ->setConstructorArgs([$this->getConnection('test')]) - ->onlyMethods(['getAuthFilePath', 'deleteAuthFile', 'writeAuthFile']) - ->getMock(); - parent::setUp(); } From a47bc4d352da33cb1b89916d1269fa5eea16bf13 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 16:12:46 +0200 Subject: [PATCH 24/52] `AbstractBackupUtility::getDriver()` no longer accepts a connection as an argument, but directly uses the one set by the configuration; --- CHANGELOG.md | 3 ++- src/Utility/AbstractBackupUtility.php | 18 +++++++----------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55d0806d..d5a9a7b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,8 @@ * added the `AbstractBackupUtility` abstract class that provides the code common to `BackupExport` and `BackupImport`; * removed `$Driver` public property for `BackupExport`/`BackupImport` and added `AbstractBackupUtility::getDriver()` method; * `Driver::_exec()` method has become `AbstractBackupUtility::getProcess()`; -* `BackupTrait::getDriver()` method has become `AbstractBackupUtility::getDriver()`; +* `BackupTrait::getDriver()` method has become `AbstractBackupUtility::getDriver()` and it no longer accepts a connection + as an argument, but directly uses the one set by the configuration; * the `BackupExport::export()` and `BackupImport::import()` methods can return the filename path on success or `false` if the `Backup.beforeExport`/`Backup.beforeImport` events are stopped; * `Driver::_getExecutable()`, `Driver::_getExportExecutable()` and `Driver::_getImportExecutable()` have become diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index 1855e5ff..1d409b56 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -51,24 +51,20 @@ abstract class AbstractBackupUtility abstract public function filename(string $filename); /** - * Gets the `Driver` instance, containing all methods to export/import database backups. - * - * You can pass a `Connection` instance. By default, the connection set in the configuration will be used. - * @param \Cake\Datasource\ConnectionInterface|null $connection A `Connection` instance + * Gets the `Driver` instance, containing all methods to export/import database backups * @return \DatabaseBackup\Driver\Driver A `Driver` instance * @throws \ErrorException|\ReflectionException * @since 2.0.0 */ - public function getDriver(?ConnectionInterface $connection = null): Driver + public function getDriver(): Driver { if (empty($this->Driver)) { - $connection = $connection ?: $this->getConnection(); - $name = $this->getDriverName($connection); - /** @var class-string<\DatabaseBackup\Driver\Driver> $Driver */ - $Driver = App::classname('DatabaseBackup.' . $name, 'Driver'); - Exceptionist::isTrue($Driver, __d('database_backup', 'The `{0}` driver does not exist', $name)); + $name = $this->getDriverName($this->getConnection()); + /** @var class-string<\DatabaseBackup\Driver\Driver> $className */ + $className = App::classname('DatabaseBackup.' . $name, 'Driver'); + Exceptionist::isTrue($className, __d('database_backup', 'The `{0}` driver does not exist', $name)); - $this->Driver = new $Driver($connection); + $this->Driver = new $className($this->getConnection()); } return $this->Driver; From 4073c4e56ab4cb8d516ff5171f6d019c0440d347 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 16:14:00 +0200 Subject: [PATCH 25/52] removed the `$BackupManager` property --- src/Utility/BackupExport.php | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/Utility/BackupExport.php b/src/Utility/BackupExport.php index 610b66b9..e579debf 100644 --- a/src/Utility/BackupExport.php +++ b/src/Utility/BackupExport.php @@ -24,11 +24,6 @@ */ class BackupExport extends AbstractBackupUtility { - /** - * @var \DatabaseBackup\Utility\BackupManager - */ - public BackupManager $BackupManager; - /** * Compression type * @var string|null @@ -59,14 +54,6 @@ class BackupExport extends AbstractBackupUtility */ protected int $rotate = 0; - /** - * Construct - */ - public function __construct() - { - $this->BackupManager = new BackupManager(); - } - /** * Sets the compression. * @@ -193,10 +180,10 @@ public function export() $this->getDriver()->dispatchEvent('Backup.afterExport'); if ($this->emailRecipient) { - $this->BackupManager->send($filename, $this->emailRecipient); + BackupManager::send($filename, $this->emailRecipient); } if ($this->rotate) { - $this->BackupManager->rotate($this->rotate); + BackupManager::rotate($this->rotate); } return $filename; From cf34b8ef7fbcdbe0ad4e8209992a6d4ed481fef5 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 16:20:12 +0200 Subject: [PATCH 26/52] `BackupTrait::getDriverName()` and `AbstractBackupUtility::getDriver()` no longer accept a connection as argument, but directly use the one set by the configuration --- CHANGELOG.md | 5 +++-- src/BackupTrait.php | 11 +++-------- src/Driver/Driver.php | 6 +++--- src/Utility/AbstractBackupUtility.php | 2 +- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5a9a7b0..bc6ff93c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,9 @@ * added the `AbstractBackupUtility` abstract class that provides the code common to `BackupExport` and `BackupImport`; * removed `$Driver` public property for `BackupExport`/`BackupImport` and added `AbstractBackupUtility::getDriver()` method; * `Driver::_exec()` method has become `AbstractBackupUtility::getProcess()`; -* `BackupTrait::getDriver()` method has become `AbstractBackupUtility::getDriver()` and it no longer accepts a connection - as an argument, but directly uses the one set by the configuration; +* `BackupTrait::getDriver()` method has become `AbstractBackupUtility::getDriver()`; +* `BackupTrait::getDriverName()` and `AbstractBackupUtility::getDriver()` no longer accept a connection as argument, but + directly use the one set by the configuration; * the `BackupExport::export()` and `BackupImport::import()` methods can return the filename path on success or `false` if the `Backup.beforeExport`/`Backup.beforeImport` events are stopped; * `Driver::_getExecutable()`, `Driver::_getExportExecutable()` and `Driver::_getImportExecutable()` have become diff --git a/src/BackupTrait.php b/src/BackupTrait.php index d89c04a3..fec35ad1 100644 --- a/src/BackupTrait.php +++ b/src/BackupTrait.php @@ -59,19 +59,14 @@ public static function getConnection(?string $name = null): ConnectionInterface } /** - * Gets the driver name, according to the connection. - * - * You can pass a `Connection` instance. By default, the connection set in the configuration will be used. - * @param \Cake\Datasource\ConnectionInterface|null $connection A `Connection` instance + * Gets the driver name, according to the connection * @return string Driver name * @throws \ReflectionException * @since 2.9.2 */ - public static function getDriverName(?ConnectionInterface $connection = null): string + public static function getDriverName(): string { - $connection = $connection ?: self::getConnection(); - - return get_class_short_name($connection->getDriver()); + return get_class_short_name(self::getConnection()->getDriver()); } /** diff --git a/src/Driver/Driver.php b/src/Driver/Driver.php index 81cbae7a..199e8b36 100644 --- a/src/Driver/Driver.php +++ b/src/Driver/Driver.php @@ -80,16 +80,16 @@ final public function implementedEvents(): array protected function getExecutable(string $type): string { Exceptionist::inArray($type, ['export', 'import']); - $driver = strtolower(self::getDriverName()); + $driverName = strtolower(self::getDriverName()); $replacements = [ - '{{BINARY}}' => escapeshellarg($this->getBinary(DATABASE_BACKUP_EXECUTABLES[$driver][$type])), + '{{BINARY}}' => escapeshellarg($this->getBinary(DATABASE_BACKUP_EXECUTABLES[$driverName][$type])), '{{AUTH_FILE}}' => method_exists($this, 'getAuthFilePath') && $this->getAuthFilePath() ? escapeshellarg($this->getAuthFilePath()) : '', '{{DB_USER}}' => $this->getConfig('username'), '{{DB_PASSWORD}}' => $this->getConfig('password') ? ':' . $this->getConfig('password') : '', '{{DB_HOST}}' => $this->getConfig('host'), '{{DB_NAME}}' => $this->getConfig('database'), ]; - $exec = Configure::readOrFail('DatabaseBackup.' . $driver . '.' . $type); + $exec = Configure::readOrFail('DatabaseBackup.' . $driverName . '.' . $type); return str_replace(array_keys($replacements), $replacements, $exec); } diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index 1d409b56..8565e9aa 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -59,7 +59,7 @@ abstract public function filename(string $filename); public function getDriver(): Driver { if (empty($this->Driver)) { - $name = $this->getDriverName($this->getConnection()); + $name = $this->getDriverName(); /** @var class-string<\DatabaseBackup\Driver\Driver> $className */ $className = App::classname('DatabaseBackup.' . $name, 'Driver'); Exceptionist::isTrue($className, __d('database_backup', 'The `{0}` driver does not exist', $name)); From 8751a89e04f30514d7b35610f22d2272718bc24c Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 16:21:23 +0200 Subject: [PATCH 27/52] fixed --- src/Utility/AbstractBackupUtility.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index 8565e9aa..7d082552 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -17,7 +17,6 @@ use Cake\Core\App; use Cake\Core\Configure; -use Cake\Datasource\ConnectionInterface; use DatabaseBackup\BackupTrait; use DatabaseBackup\Driver\Driver; use Symfony\Component\Process\Process; From 76c9d0c53f9d978ffd622ba927b16ffdad02f9c6 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 16:28:31 +0200 Subject: [PATCH 28/52] the `Driver` class no longer accepts a connection as constructor argument, but directly uses the one set by the configuration --- CHANGELOG.md | 1 + src/Driver/Driver.php | 18 +++++------------- tests/TestCase/Driver/DriverTest.php | 10 ---------- 3 files changed, 6 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc6ff93c..dafd0bbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * `BackupTrait::getDriver()` method has become `AbstractBackupUtility::getDriver()`; * `BackupTrait::getDriverName()` and `AbstractBackupUtility::getDriver()` no longer accept a connection as argument, but directly use the one set by the configuration; +* the `Driver` class no longer accepts a connection as constructor argument, but directly uses the one set by the configuration; * the `BackupExport::export()` and `BackupImport::import()` methods can return the filename path on success or `false` if the `Backup.beforeExport`/`Backup.beforeImport` events are stopped; * `Driver::_getExecutable()`, `Driver::_getExportExecutable()` and `Driver::_getImportExecutable()` have become diff --git a/src/Driver/Driver.php b/src/Driver/Driver.php index 199e8b36..43c60691 100644 --- a/src/Driver/Driver.php +++ b/src/Driver/Driver.php @@ -31,19 +31,11 @@ abstract class Driver implements EventListenerInterface use BackupTrait; use EventDispatcherTrait; - /** - * @var \Cake\Database\Connection - */ - protected Connection $connection; - /** * Constructor - * @param \Cake\Database\Connection $connection A `Connection` instance */ - public function __construct(Connection $connection) + public function __construct() { - $this->connection = $connection; - //Attaches the object to the event manager $this->getEventManager()->on($this); } @@ -77,7 +69,7 @@ final public function implementedEvents(): array * @throws \ReflectionException * @throws \ErrorException */ - protected function getExecutable(string $type): string + private function getExecutable(string $type): string { Exceptionist::inArray($type, ['export', 'import']); $driverName = strtolower(self::getDriverName()); @@ -176,7 +168,7 @@ public function beforeImport(): bool * @return string * @throws \ErrorException */ - final public function getBinary(string $name): string + public function getBinary(string $name): string { return Exceptionist::isTrue(Configure::read('DatabaseBackup.binaries.' . $name), 'Binary for `' . $name . '` could not be found. You have to set its path manually'); } @@ -187,8 +179,8 @@ final public function getBinary(string $name): string * @return mixed Config value or `null` if the key doesn't exist * @since 2.3.0 */ - final public function getConfig(string $key) + protected function getConfig(string $key) { - return $this->connection->config()[$key] ?? null; + return $this->getConnection()->config()[$key] ?? null; } } diff --git a/tests/TestCase/Driver/DriverTest.php b/tests/TestCase/Driver/DriverTest.php index 206e72a1..c4f60589 100644 --- a/tests/TestCase/Driver/DriverTest.php +++ b/tests/TestCase/Driver/DriverTest.php @@ -55,14 +55,4 @@ public function testGetBinary(): void $this->expectExceptionMessage('Binary for `noExisting` could not be found. You have to set its path manually'); $this->Driver->getBinary('noExisting'); } - - /** - * @test - * @uses \DatabaseBackup\Driver\Driver::getConfig() - */ - public function testGetConfig(): void - { - $this->assertNotEmpty($this->Driver->getConfig('name')); - $this->assertNull($this->Driver->getConfig('noExistingKey')); - } } From e59b27a2c402c87bc5995aba38665aee138e78c5 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 16:52:40 +0200 Subject: [PATCH 29/52] fixed --- src/Driver/Driver.php | 1 - tests/TestCase/Driver/MysqlTest.php | 29 ++++++++++------------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/Driver/Driver.php b/src/Driver/Driver.php index 43c60691..7125de30 100644 --- a/src/Driver/Driver.php +++ b/src/Driver/Driver.php @@ -16,7 +16,6 @@ namespace DatabaseBackup\Driver; use Cake\Core\Configure; -use Cake\Database\Connection; use Cake\Event\EventDispatcherTrait; use Cake\Event\EventListenerInterface; use DatabaseBackup\BackupTrait; diff --git a/tests/TestCase/Driver/MysqlTest.php b/tests/TestCase/Driver/MysqlTest.php index 2595e569..7fb11685 100644 --- a/tests/TestCase/Driver/MysqlTest.php +++ b/tests/TestCase/Driver/MysqlTest.php @@ -36,17 +36,14 @@ class MysqlTest extends DriverTestCase */ public function setUp(): void { - $this->Driver ??= $this->getMockBuilder(Mysql::class) - ->setConstructorArgs([$this->getConnection('test')]) - ->onlyMethods(['getAuthFilePath', 'deleteAuthFile', 'writeAuthFile']) - ->getMock(); + $this->Driver ??= $this->createPartialMock(Mysql::class, ['getAuthFilePath', 'writeAuthFile']); - $connection = $this->getConnection('test'); - - if (get_class_short_name($connection->getDriver()) !== 'Mysql') { + if (!$this->Driver instanceof Mysql) { $this->markTestSkipped('Skipping tests for Mysql, current driver is ' . $this->Driver->getDriverName()); } + $this->Driver->getEventManager()->on($this->Driver); + parent::setUp(); } @@ -59,10 +56,8 @@ public function testAfterExport(): void $expectedAuthFile = Filesystem::createTmpFile(); $this->assertFileExists($expectedAuthFile); - $Driver = $this->getMockBuilder(Mysql::class) - ->setConstructorArgs([$this->getConnection('test')]) - ->onlyMethods(['getAuthFilePath']) - ->getMock(); + $Driver = $this->createPartialMock(Mysql::class, ['getAuthFilePath']); + $Driver->getEventManager()->on($Driver); $Driver->method('getAuthFilePath')->willReturn($expectedAuthFile); $Driver->dispatchEvent('Backup.afterExport'); $this->assertFileDoesNotExist($expectedAuthFile); @@ -77,10 +72,8 @@ public function testAfterImport(): void $expectedAuthFile = Filesystem::createTmpFile(); $this->assertFileExists($expectedAuthFile); - $Driver = $this->getMockBuilder(Mysql::class) - ->setConstructorArgs([$this->getConnection('test')]) - ->onlyMethods(['getAuthFilePath']) - ->getMock(); + $Driver = $this->createPartialMock(Mysql::class, ['getAuthFilePath']); + $Driver->getEventManager()->on($Driver); $Driver->method('getAuthFilePath')->willReturn($expectedAuthFile); $Driver->dispatchEvent('Backup.afterImport'); $this->assertFileDoesNotExist($expectedAuthFile); @@ -133,10 +126,8 @@ public function testWriteAuthFile(): void $expectedAuthFile = TMP . 'auth' . uniqid(); $this->assertFileDoesNotExist($expectedAuthFile); - $Driver = $this->getMockBuilder(Mysql::class) - ->setConstructorArgs([$this->getConnection('test')]) - ->onlyMethods(['getAuthFilePath']) - ->getMock(); + $Driver = $this->createPartialMock(Mysql::class, ['getAuthFilePath']); + $Driver->getEventManager()->on($Driver); $Driver->method('getAuthFilePath')->willReturn($expectedAuthFile); //Dispatches an event that calls and returns `writeAuthFile()` From 0be0642de235cd74c8b69f73f0a2d3ce167577d8 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 17:03:17 +0200 Subject: [PATCH 30/52] removed useless `TestCase::getMockForAbstractDriver()` method --- CHANGELOG.md | 1 + src/TestSuite/TestCase.php | 4 +--- tests/TestCase/Driver/DriverTest.php | 3 ++- tests/TestCase/Utility/BackupExportTest.php | 4 +++- tests/TestCase/Utility/BackupImportTest.php | 4 +++- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dafd0bbc..9eb7c71d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ `BackupImport::import()` and therefore those methods no longer exist; * `MySql::getAuthFile()` method has become `getAuthFilePath()`, to be more understandable; * `MySql::deleteAuthFile()` method returns void (there is no need for it to return anything); +* removed useless `TestCase::getMockForAbstractDriver()` method; * removed useless `BackupExport::$config` property; * completely improved the `BackupImportTest` tests. diff --git a/src/TestSuite/TestCase.php b/src/TestSuite/TestCase.php index d97bdfff..cd5af8cd 100644 --- a/src/TestSuite/TestCase.php +++ b/src/TestSuite/TestCase.php @@ -45,10 +45,8 @@ public function tearDown(): void */ protected function getMockForAbstractDriver(array $mockedMethods = []): Driver { - /** @var \Cake\Database\Connection $Connection */ - $Connection = $this->getConnection('test'); /** @var \DatabaseBackup\Driver\Driver&\PHPUnit\Framework\MockObject\MockObject $Driver */ - $Driver = $this->createPartialMockForAbstractClass(Driver::class, $mockedMethods, [$Connection]); + $Driver = $this->createPartialMockForAbstractClass(Driver::class, $mockedMethods); return $Driver; } diff --git a/tests/TestCase/Driver/DriverTest.php b/tests/TestCase/Driver/DriverTest.php index c4f60589..276b8ff2 100644 --- a/tests/TestCase/Driver/DriverTest.php +++ b/tests/TestCase/Driver/DriverTest.php @@ -17,6 +17,7 @@ namespace DatabaseBackup\Test\TestCase\Driver; use DatabaseBackup\Driver\Driver; +use DatabaseBackup\Driver\Sqlite; use DatabaseBackup\TestSuite\TestCase; /** @@ -40,7 +41,7 @@ public function setUp(): void { parent::setUp(); - $this->Driver ??= $this->getMockForAbstractDriver(); + $this->Driver ??= $this->createPartialMock(Sqlite::class, []); } /** diff --git a/tests/TestCase/Utility/BackupExportTest.php b/tests/TestCase/Utility/BackupExportTest.php index f807ed21..296d203e 100644 --- a/tests/TestCase/Utility/BackupExportTest.php +++ b/tests/TestCase/Utility/BackupExportTest.php @@ -18,6 +18,7 @@ use Cake\Core\Configure; use Cake\Event\EventList; use Cake\TestSuite\EmailTrait; +use DatabaseBackup\Driver\Sqlite; use DatabaseBackup\TestSuite\TestCase; use DatabaseBackup\Utility\BackupExport; use Symfony\Component\Process\Exception\ProcessTimedOutException; @@ -189,8 +190,9 @@ public function testExportWithDifferentChmod(): void */ public function testExportStoppedByBeforeExport(): void { - $Driver = $this->getMockForAbstractDriver(['beforeExport']); + $Driver = $this->createPartialMock(Sqlite::class, ['beforeExport']); $Driver->method('beforeExport')->willReturn(false); + $Driver->getEventManager()->on($Driver); $BackupExport = $this->createPartialMock(BackupExport::class, ['getDriver']); $BackupExport->method('getDriver')->willReturn($Driver); $this->assertFalse($BackupExport->export()); diff --git a/tests/TestCase/Utility/BackupImportTest.php b/tests/TestCase/Utility/BackupImportTest.php index f8162ecd..ba8b642c 100644 --- a/tests/TestCase/Utility/BackupImportTest.php +++ b/tests/TestCase/Utility/BackupImportTest.php @@ -16,6 +16,7 @@ namespace DatabaseBackup\Test\TestCase\Utility; use Cake\Event\EventList; +use DatabaseBackup\Driver\Sqlite; use DatabaseBackup\TestSuite\TestCase; use DatabaseBackup\Utility\BackupImport; use Symfony\Component\Process\Exception\ProcessTimedOutException; @@ -102,8 +103,9 @@ public function testImport(): void */ public function testImportStoppedByBeforeExport(): void { - $Driver = $this->getMockForAbstractDriver(['beforeImport']); + $Driver = $this->createPartialMock(Sqlite::class, ['beforeImport']); $Driver->method('beforeImport')->willReturn(false); + $Driver->getEventManager()->on($Driver); $BackupImport = $this->createPartialMock(BackupImport::class, ['getDriver']); $BackupImport->method('getDriver')->willReturn($Driver); $this->assertFalse($BackupImport->filename(createBackup())->import()); From 4fe782cee6db1fed5abcd40c5c09ca935fa3ba4c Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 17:03:28 +0200 Subject: [PATCH 31/52] removed useless `TestCase::getMockForAbstractDriver()` method --- src/TestSuite/TestCase.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/TestSuite/TestCase.php b/src/TestSuite/TestCase.php index cd5af8cd..f725489c 100644 --- a/src/TestSuite/TestCase.php +++ b/src/TestSuite/TestCase.php @@ -16,7 +16,6 @@ namespace DatabaseBackup\TestSuite; use DatabaseBackup\BackupTrait; -use DatabaseBackup\Driver\Driver; use DatabaseBackup\Utility\BackupManager; use MeTools\TestSuite\TestCase as BaseTestCase; @@ -37,17 +36,4 @@ public function tearDown(): void parent::tearDown(); } - - /** - * Internal method to get a mock for `Driver` abstract class - * @param array $mockedMethods Mocked methods - * @return \DatabaseBackup\Driver\Driver&\PHPUnit\Framework\MockObject\MockObject - */ - protected function getMockForAbstractDriver(array $mockedMethods = []): Driver - { - /** @var \DatabaseBackup\Driver\Driver&\PHPUnit\Framework\MockObject\MockObject $Driver */ - $Driver = $this->createPartialMockForAbstractClass(Driver::class, $mockedMethods); - - return $Driver; - } } From 6c268761beb1822a8035d0e204f641f67ddf64db Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 17:03:39 +0200 Subject: [PATCH 32/52] fixed --- src/TestSuite/TestCase.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TestSuite/TestCase.php b/src/TestSuite/TestCase.php index f725489c..4030b55b 100644 --- a/src/TestSuite/TestCase.php +++ b/src/TestSuite/TestCase.php @@ -32,8 +32,8 @@ abstract class TestCase extends BaseTestCase */ public function tearDown(): void { - BackupManager::deleteAll(); - parent::tearDown(); + + BackupManager::deleteAll(); } } From 639bccc8c438e79dde1bf60edaaa286a4fa5988b Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 18:11:35 +0200 Subject: [PATCH 33/52] improved the `ExportCommand` class --- CHANGELOG.md | 1 + src/Command/ExportCommand.php | 23 +++++------------------ 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9eb7c71d..e3d96bd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ * `MySql::deleteAuthFile()` method returns void (there is no need for it to return anything); * removed useless `TestCase::getMockForAbstractDriver()` method; * removed useless `BackupExport::$config` property; +* improved the `ExportCommand` class; * completely improved the `BackupImportTest` tests. ## 2.11 branch diff --git a/src/Command/ExportCommand.php b/src/Command/ExportCommand.php index f9ffcfd1..b8a313a8 100644 --- a/src/Command/ExportCommand.php +++ b/src/Command/ExportCommand.php @@ -78,6 +78,7 @@ public function execute(Arguments $args, ConsoleIo $io): void try { $BackupExport = new BackupExport(); + //Sets the output filename or the compression type. Regarding the `rotate` option, the //`BackupShell::rotate()` method will be called at the end, instead of `BackupExport::rotate()` if ($args->getOption('filename')) { @@ -94,27 +95,13 @@ public function execute(Arguments $args, ConsoleIo $io): void Exceptionist::isTrue($file, __d('database_backup', 'The `{0}` event stopped the operation', 'Backup.beforeExport')); $io->success(__d('database_backup', 'Backup `{0}` has been exported', rtr($file))); - $verbose = $args->getOption('verbose'); - $quiet = $args->getOption('quiet'); - - //Sends via email + //Sends via email and/or rotates + $extraOptions = array_filter([$args->getOption('verbose') ? '--verbose' : '', $args->getOption('quiet') ? '--quiet' : '']); if ($args->getOption('send')) { - $SendCommand = new SendCommand(); - $SendCommand->execute(new Arguments( - [$file, (string)$args->getOption('send')], - compact('verbose', 'quiet'), - $SendCommand->getOptionParser()->argumentNames() - ), $io); + $this->executeCommand(SendCommand::class, array_merge([$file, (string)$args->getOption('send')], $extraOptions), $io); } - - //Rotates if ($args->getOption('rotate')) { - $RotateCommand = new RotateCommand(); - $RotateCommand->execute(new Arguments( - [(string)$args->getOption('rotate')], - compact('verbose', 'quiet'), - $RotateCommand->getOptionParser()->argumentNames() - ), $io); + $this->executeCommand(RotateCommand::class, array_merge([(string)$args->getOption('rotate')], $extraOptions), $io); } } catch (Exception $e) { $io->error($e->getMessage()); From 63613836938d786b6cef5971e2849a84b46303e9 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 18:42:16 +0200 Subject: [PATCH 34/52] fixed --- src/Driver/Sqlite.php | 10 ++-- src/TestSuite/DriverTestCase.php | 9 ++- tests/TestCase/BackupTraitTest.php | 2 +- tests/TestCase/Command/IndexCommandTest.php | 20 +++---- tests/TestCase/Command/RotateCommandTest.php | 18 +++--- tests/TestCase/Driver/DriverTest.php | 59 -------------------- tests/TestCase/Driver/MysqlTest.php | 12 ++-- tests/TestCase/Driver/PostgresTest.php | 4 +- tests/TestCase/Driver/SqliteTest.php | 4 +- 9 files changed, 37 insertions(+), 101 deletions(-) delete mode 100644 tests/TestCase/Driver/DriverTest.php diff --git a/src/Driver/Sqlite.php b/src/Driver/Sqlite.php index 2546333b..939cfe1b 100644 --- a/src/Driver/Sqlite.php +++ b/src/Driver/Sqlite.php @@ -27,17 +27,19 @@ class Sqlite extends Driver */ public function beforeImport(): bool { + /** @var \Cake\Database\Connection $connection */ + $connection = $this->getConnection(); /** @var \Cake\Database\Schema\Collection $schemaCollection */ - $schemaCollection = $this->connection->getSchemaCollection(); + $schemaCollection = $connection->getSchemaCollection(); //Drops each table foreach ($schemaCollection->listTables() as $table) { - array_map([$this->connection, 'execute'], $schemaCollection->describe($table)->dropSql($this->connection)); + array_map([$connection, 'execute'], $schemaCollection->describe($table)->dropSql($connection)); } //Needs disconnect and re-connect because the database schema has changed - $this->connection->disconnect(); - $this->connection->connect(); + $connection->disconnect(); + $connection->connect(); return true; } diff --git a/src/TestSuite/DriverTestCase.php b/src/TestSuite/DriverTestCase.php index e232206b..e4ff66fb 100644 --- a/src/TestSuite/DriverTestCase.php +++ b/src/TestSuite/DriverTestCase.php @@ -40,13 +40,12 @@ public function setUp(): void parent::setUp(); if (empty($this->Driver)) { - /** @var \Cake\Database\Connection $connection */ - $connection = $this->getConnection('test'); - /** @var class-string<\DatabaseBackup\Driver\Driver> $DriverClass */ - $DriverClass = App::className('DatabaseBackup.' . get_class_short_name($connection->config()['driver']), 'Driver'); - $this->Driver = new $DriverClass($connection); + $DriverClass = App::className('DatabaseBackup.' . $this->getDriverName(), 'Driver'); + $this->Driver = new $DriverClass(); } + + $this->Driver->getEventManager()->on($this->Driver); } /** diff --git a/tests/TestCase/BackupTraitTest.php b/tests/TestCase/BackupTraitTest.php index ba16919f..eb7e9174 100644 --- a/tests/TestCase/BackupTraitTest.php +++ b/tests/TestCase/BackupTraitTest.php @@ -46,7 +46,7 @@ public function setUp(): void { parent::setUp(); - $this->Trait = $this->Trait ?: $this->getMockForTrait(BackupTrait::class); + $this->Trait ??= $this->getMockForTrait(BackupTrait::class); } /** diff --git a/tests/TestCase/Command/IndexCommandTest.php b/tests/TestCase/Command/IndexCommandTest.php index 63fd1862..68cf3702 100644 --- a/tests/TestCase/Command/IndexCommandTest.php +++ b/tests/TestCase/Command/IndexCommandTest.php @@ -16,7 +16,6 @@ namespace DatabaseBackup\Test\TestCase\Command; use DatabaseBackup\TestSuite\CommandTestCase; -use DatabaseBackup\Utility\BackupManager; /** * IndexCommandTest class @@ -27,8 +26,16 @@ class IndexCommandTest extends CommandTestCase * @test * @uses \DatabaseBackup\Command\IndexCommand::execute() */ - public function testExecute(): void + public function testExecuteWithNoBackups(): void { + //With no backups + $this->exec('database_backup.index -v'); + $this->assertExitSuccess(); + $this->assertOutputContains('Connection: test'); + $this->assertOutputRegExp('/Driver: (Mysql|Postgres|Sqlite)/'); + $this->assertOutputContains('Backup files found: 0'); + $this->assertErrorEmpty(); + createSomeBackups(); $this->exec('database_backup.index -v'); $this->assertExitSuccess(); @@ -37,14 +44,5 @@ public function testExecute(): void $this->assertOutputRegExp('/backup\.sql\.bz2\s+|\s+sql\.bz2\s+|\s+bzip2\s+|\s+[\d\.]+ \w+\s+|\s+[\d\/]+, [\d:]+ (AP)M/'); $this->assertOutputRegExp('/backup\.sq\s+|\s+sql\s+|\s+|\s+[\d\.]+ \w+\s+|\s+[\d\/]+, [\d:]+ (AP)M/'); $this->assertErrorEmpty(); - - //With no backups - BackupManager::deleteAll(); - $this->exec('database_backup.index -v'); - $this->assertExitSuccess(); - $this->assertOutputContains('Connection: test'); - $this->assertOutputRegExp('/Driver: (Mysql|Postgres|Sqlite)/'); - $this->assertOutputContains('Backup files found: 0'); - $this->assertErrorEmpty(); } } diff --git a/tests/TestCase/Command/RotateCommandTest.php b/tests/TestCase/Command/RotateCommandTest.php index d45cebf9..352d53a1 100644 --- a/tests/TestCase/Command/RotateCommandTest.php +++ b/tests/TestCase/Command/RotateCommandTest.php @@ -16,7 +16,6 @@ namespace DatabaseBackup\Test\TestCase\Command; use DatabaseBackup\TestSuite\CommandTestCase; -use DatabaseBackup\Utility\BackupManager; /** * RotateCommandTest class @@ -29,6 +28,14 @@ class RotateCommandTest extends CommandTestCase */ public function testExecute(): void { + //With no backups + $this->exec('database_backup.rotate -v 1'); + $this->assertExitSuccess(); + $this->assertOutputContains('Connection: test'); + $this->assertOutputRegExp('/Driver: (Mysql|Postgres|Sqlite)/'); + $this->assertOutputContains('No backup has been deleted'); + $this->assertErrorEmpty(); + $expectedFiles = createSomeBackups(); array_pop($expectedFiles); $this->exec('database_backup.rotate -v 1'); @@ -39,15 +46,6 @@ public function testExecute(): void $this->assertOutputContains('Deleted backup files: 2'); $this->assertErrorEmpty(); - //With no backups - BackupManager::deleteAll(); - $this->exec('database_backup.rotate -v 1'); - $this->assertExitSuccess(); - $this->assertOutputContains('Connection: test'); - $this->assertOutputRegExp('/Driver: (Mysql|Postgres|Sqlite)/'); - $this->assertOutputContains('No backup has been deleted'); - $this->assertErrorEmpty(); - //With an invalid value $this->exec('database_backup.rotate -v string'); $this->assertExitError(); diff --git a/tests/TestCase/Driver/DriverTest.php b/tests/TestCase/Driver/DriverTest.php deleted file mode 100644 index 276b8ff2..00000000 --- a/tests/TestCase/Driver/DriverTest.php +++ /dev/null @@ -1,59 +0,0 @@ -Driver ??= $this->createPartialMock(Sqlite::class, []); - } - - /** - * @test - * @uses \DatabaseBackup\Driver\Driver::getBinary() - */ - public function testGetBinary(): void - { - $this->assertStringEndsWith('mysql' . (IS_WIN ? '.exe' : ''), $this->Driver->getBinary('mysql')); - - //With a binary not available - $this->expectExceptionMessage('Binary for `noExisting` could not be found. You have to set its path manually'); - $this->Driver->getBinary('noExisting'); - } -} diff --git a/tests/TestCase/Driver/MysqlTest.php b/tests/TestCase/Driver/MysqlTest.php index 7fb11685..ba2c0362 100644 --- a/tests/TestCase/Driver/MysqlTest.php +++ b/tests/TestCase/Driver/MysqlTest.php @@ -36,13 +36,11 @@ class MysqlTest extends DriverTestCase */ public function setUp(): void { - $this->Driver ??= $this->createPartialMock(Mysql::class, ['getAuthFilePath', 'writeAuthFile']); - - if (!$this->Driver instanceof Mysql) { - $this->markTestSkipped('Skipping tests for Mysql, current driver is ' . $this->Driver->getDriverName()); + if ($this->getConnection()->config()['scheme'] !== 'mysql') { + $this->markTestSkipped('Skipping tests for mysql, current driver is `' . $this->getConnection()->config()['scheme'] . '`'); } - $this->Driver->getEventManager()->on($this->Driver); + $this->Driver ??= $this->createPartialMock(Mysql::class, ['getAuthFilePath', 'writeAuthFile']); parent::setUp(); } @@ -57,8 +55,8 @@ public function testAfterExport(): void $this->assertFileExists($expectedAuthFile); $Driver = $this->createPartialMock(Mysql::class, ['getAuthFilePath']); - $Driver->getEventManager()->on($Driver); $Driver->method('getAuthFilePath')->willReturn($expectedAuthFile); + $Driver->getEventManager()->on($Driver); $Driver->dispatchEvent('Backup.afterExport'); $this->assertFileDoesNotExist($expectedAuthFile); } @@ -127,8 +125,8 @@ public function testWriteAuthFile(): void $this->assertFileDoesNotExist($expectedAuthFile); $Driver = $this->createPartialMock(Mysql::class, ['getAuthFilePath']); - $Driver->getEventManager()->on($Driver); $Driver->method('getAuthFilePath')->willReturn($expectedAuthFile); + $Driver->getEventManager()->on($Driver); //Dispatches an event that calls and returns `writeAuthFile()` $this->assertTrue($Driver->dispatchEvent('Backup.beforeExport')->getResult()); diff --git a/tests/TestCase/Driver/PostgresTest.php b/tests/TestCase/Driver/PostgresTest.php index b7ab606b..e85c3e98 100644 --- a/tests/TestCase/Driver/PostgresTest.php +++ b/tests/TestCase/Driver/PostgresTest.php @@ -31,8 +31,8 @@ public function setUp(): void { parent::setUp(); - if (!$this->Driver instanceof Postgres) { - $this->markTestSkipped('Skipping tests for Postgres, current driver is ' . $this->Driver->getDriverName()); + if ($this->getConnection()->config()['scheme'] !== 'postgres') { + $this->markTestSkipped('Skipping tests for postgres, current driver is `' . $this->getConnection()->config()['scheme'] . '`'); } } } diff --git a/tests/TestCase/Driver/SqliteTest.php b/tests/TestCase/Driver/SqliteTest.php index cf05f24d..0dab2bc5 100644 --- a/tests/TestCase/Driver/SqliteTest.php +++ b/tests/TestCase/Driver/SqliteTest.php @@ -31,8 +31,8 @@ public function setUp(): void { parent::setUp(); - if (!$this->Driver instanceof Sqlite) { - $this->markTestSkipped('Skipping tests for Sqlite, current driver is ' . $this->Driver->getDriverName()); + if ($this->getConnection()->config()['scheme'] !== 'sqlite') { + $this->markTestSkipped('Skipping tests for sqlite, current driver is `' . $this->getConnection()->config()['scheme'] . '`'); } } } From 9948fb60af85eb4f3e679183c8273caf640557f4 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 18:46:41 +0200 Subject: [PATCH 35/52] fixed test --- tests/TestCase/Driver/MysqlTest.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/TestCase/Driver/MysqlTest.php b/tests/TestCase/Driver/MysqlTest.php index ba2c0362..73a8a4ad 100644 --- a/tests/TestCase/Driver/MysqlTest.php +++ b/tests/TestCase/Driver/MysqlTest.php @@ -131,9 +131,10 @@ public function testWriteAuthFile(): void //Dispatches an event that calls and returns `writeAuthFile()` $this->assertTrue($Driver->dispatchEvent('Backup.beforeExport')->getResult()); $this->assertFileExists($expectedAuthFile); + $config = $Driver->getConnection()->config(); $this->assertSame('[mysqldump]' . PHP_EOL . - 'user=travis' . PHP_EOL . - 'password=""' . PHP_EOL . - 'host=localhost', file_get_contents($expectedAuthFile)); + 'user=' . $config['username'] . PHP_EOL . + 'password="' . ($config['password'] ?? '') . '"' . PHP_EOL . + 'host=' . $config['host'], file_get_contents($expectedAuthFile)); } } From 41fb89f90fd27c1746d0fde55996403d2c016746 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 18:49:10 +0200 Subject: [PATCH 36/52] updated --- psalm-baseline.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 083ceba8..c5f2e626 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,10 +1,21 @@ + + + $this->auth + TMP . uniqid('auth') + + empty($this->Driver) + + + empty($this->Driver) + + $this->defaultExtension From 331da9fce08df06367c169ae41fb84cc53345139 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Mon, 5 Jun 2023 18:50:55 +0200 Subject: [PATCH 37/52] fixed --- tests/TestCase/Driver/PostgresTest.php | 2 -- tests/TestCase/Driver/SqliteTest.php | 2 -- 2 files changed, 4 deletions(-) diff --git a/tests/TestCase/Driver/PostgresTest.php b/tests/TestCase/Driver/PostgresTest.php index e85c3e98..8b4143ce 100644 --- a/tests/TestCase/Driver/PostgresTest.php +++ b/tests/TestCase/Driver/PostgresTest.php @@ -1,5 +1,4 @@ Date: Tue, 6 Jun 2023 15:26:24 +0200 Subject: [PATCH 38/52] added configuration for `DatabaseBackup.processTimeout` --- config/bootstrap.php | 1 + src/Utility/AbstractBackupUtility.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config/bootstrap.php b/config/bootstrap.php index 60e5af19..398ea81e 100644 --- a/config/bootstrap.php +++ b/config/bootstrap.php @@ -40,6 +40,7 @@ $defaults = [ 'DatabaseBackup.connection' => 'default', 'DatabaseBackup.chmod' => 0664, + 'DatabaseBackup.processTimeout' => 60, 'DatabaseBackup.target' => ROOT . 'backups', 'DatabaseBackup.mysql.export' => '{{BINARY}} --defaults-file={{AUTH_FILE}} {{DB_NAME}}', 'DatabaseBackup.mysql.import' => '{{BINARY}} --defaults-extra-file={{AUTH_FILE}} {{DB_NAME}}', diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index 7d082552..b4ea7fcd 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -78,7 +78,7 @@ public function getDriver(): Driver protected function getProcess(string $command): Process { $Process = Process::fromShellCommandline($command); - $Process->setTimeout(Configure::read('DatabaseBackup.processTimeout', 60)); + $Process->setTimeout(Configure::readOrFail('DatabaseBackup.processTimeout')); $Process->run(); return $Process; From 0f3d3dac61fa1c0fd215061513f1d87e15ab3e7e Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Tue, 6 Jun 2023 15:50:05 +0200 Subject: [PATCH 39/52] added `AbstractBackupUtility::timeout()` method, so now the `BackupExport`/`BackupImport` utilities have a method to set the timeout for shell commands at runtime --- CHANGELOG.md | 2 ++ src/Utility/AbstractBackupUtility.php | 20 +++++++++++++++++++- tests/TestCase/Utility/BackupExportTest.php | 10 ++++++++++ tests/TestCase/Utility/BackupImportTest.php | 10 ++++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3d96bd4..49113021 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # 2.x branch ## 2.12 branch ### 2.12.0 +* added `AbstractBackupUtility::timeout()` method, so now the `BackupExport`/`BackupImport` utilities have a method to + set the timeout for shell commands at runtime; * the events (`Backup.beforeExport`, `Backup.afterExport`, `Backup.beforeImport`, `Backup.afterImport`, which remain implemented by the driver classes) are directly dispatched by the `BackupExport::export()` and `BackupImport::import()` methods, and no longer by the drivers themselves; diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index b4ea7fcd..7b2e6f51 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -37,6 +37,12 @@ abstract class AbstractBackupUtility */ protected string $filename; + /** + * Timeout for shell commands + * @var int + */ + protected int $timeout; + /** * @var \DatabaseBackup\Driver\Driver */ @@ -49,6 +55,18 @@ abstract class AbstractBackupUtility */ abstract public function filename(string $filename); + /** + * Sets the timeout for shell commands + * @param int $timeout Timeout in seconds + * @return $this + */ + public function timeout(int $timeout) + { + $this->timeout = $timeout; + + return $this; + } + /** * Gets the `Driver` instance, containing all methods to export/import database backups * @return \DatabaseBackup\Driver\Driver A `Driver` instance @@ -78,7 +96,7 @@ public function getDriver(): Driver protected function getProcess(string $command): Process { $Process = Process::fromShellCommandline($command); - $Process->setTimeout(Configure::readOrFail('DatabaseBackup.processTimeout')); + $Process->setTimeout($this->timeout ?? Configure::readOrFail('DatabaseBackup.processTimeout')); $Process->run(); return $Process; diff --git a/tests/TestCase/Utility/BackupExportTest.php b/tests/TestCase/Utility/BackupExportTest.php index 296d203e..b2dbe469 100644 --- a/tests/TestCase/Utility/BackupExportTest.php +++ b/tests/TestCase/Utility/BackupExportTest.php @@ -132,6 +132,16 @@ public function testSend(): void $this->assertSame($recipient, $this->getProperty($this->BackupExport, 'emailRecipient')); } + /** + * @test + * @uses \DatabaseBackup\Utility\BackupExport::timeout() + */ + public function testTimeout(): void + { + $this->BackupExport->timeout(120); + $this->assertSame(120, $this->getProperty($this->BackupExport, 'timeout')); + } + /** * @test * @uses \DatabaseBackup\Utility\BackupExport::export() diff --git a/tests/TestCase/Utility/BackupImportTest.php b/tests/TestCase/Utility/BackupImportTest.php index ba8b642c..612c0e00 100644 --- a/tests/TestCase/Utility/BackupImportTest.php +++ b/tests/TestCase/Utility/BackupImportTest.php @@ -77,6 +77,16 @@ public function testFilename(): void $this->BackupImport->filename(Filesystem::createTmpFile()); } + /** + * @test + * @uses \DatabaseBackup\Utility\BackupImport::timeout() + */ + public function testTimeout(): void + { + $this->BackupImport->timeout(120); + $this->assertSame(120, $this->getProperty($this->BackupImport, 'timeout')); + } + /** * @test * @uses \DatabaseBackup\Utility\BackupImport::import() From a67adcfec68d278a70512b11ad8071ac7cc0bb95 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Tue, 6 Jun 2023 15:54:32 +0200 Subject: [PATCH 40/52] fixed --- tests/TestCase/Command/IndexCommandTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TestCase/Command/IndexCommandTest.php b/tests/TestCase/Command/IndexCommandTest.php index 68cf3702..4d9d857e 100644 --- a/tests/TestCase/Command/IndexCommandTest.php +++ b/tests/TestCase/Command/IndexCommandTest.php @@ -26,7 +26,7 @@ class IndexCommandTest extends CommandTestCase * @test * @uses \DatabaseBackup\Command\IndexCommand::execute() */ - public function testExecuteWithNoBackups(): void + public function testExecute(): void { //With no backups $this->exec('database_backup.index -v'); From 051003845f08b71fb718380e6029c9e5c23ef774 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Tue, 6 Jun 2023 15:55:53 +0200 Subject: [PATCH 41/52] Added `--timeout` option (short: `-t`) for `ExportCommand`/`ImportCommand` --- CHANGELOG.md | 4 +-- src/Command/ExportCommand.php | 14 +++++++--- src/Command/ImportCommand.php | 16 ++++++++--- src/Console/Command.php | 5 ++++ tests/TestCase/Command/ExportCommandTest.php | 29 ++++++++++++++------ tests/TestCase/Command/ImportCommandTest.php | 23 ++++++++++++++-- 6 files changed, 71 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49113021..410824d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # 2.x branch ## 2.12 branch ### 2.12.0 -* added `AbstractBackupUtility::timeout()` method, so now the `BackupExport`/`BackupImport` utilities have a method to - set the timeout for shell commands at runtime; +* added `AbstractBackupUtility::timeout()` method, so now `BackupExport`/`BackupImport` utilities have a method to set the + timeout for shell commands at runtime. Added `--timeout` option (short: `-t`) for `ExportCommand`/`ImportCommand`; * the events (`Backup.beforeExport`, `Backup.afterExport`, `Backup.beforeImport`, `Backup.afterImport`, which remain implemented by the driver classes) are directly dispatched by the `BackupExport::export()` and `BackupImport::import()` methods, and no longer by the drivers themselves; diff --git a/src/Command/ExportCommand.php b/src/Command/ExportCommand.php index b8a313a8..d4a747e9 100644 --- a/src/Command/ExportCommand.php +++ b/src/Command/ExportCommand.php @@ -18,6 +18,7 @@ use Cake\Console\Arguments; use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; +use Cake\Core\Configure; use DatabaseBackup\Console\Command; use DatabaseBackup\Utility\BackupExport; use Exception; @@ -58,6 +59,10 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption 'to indicate the recipient\'s email address'), 'short' => 's', ], + 'timeout' => [ + 'help' => __d('database_backup', 'Timeout for shell commands. Default value: {0} seconds', Configure::readOrFail('DatabaseBackup.processTimeout')), + 'short' => 't', + ], ]); } @@ -86,11 +91,12 @@ public function execute(Arguments $args, ConsoleIo $io): void } elseif ($args->getOption('compression')) { $BackupExport->compression((string)$args->getOption('compression')); } + //Sets the timeout + if ($args->getOption('timeout')) { + $BackupExport->timeout((int)$args->getOption('timeout')); + } - /** - * Exports - * @var string $file - */ + /** @var string $file */ $file = $BackupExport->export(); Exceptionist::isTrue($file, __d('database_backup', 'The `{0}` event stopped the operation', 'Backup.beforeExport')); $io->success(__d('database_backup', 'Backup `{0}` has been exported', rtr($file))); diff --git a/src/Command/ImportCommand.php b/src/Command/ImportCommand.php index 3890da6e..08580139 100644 --- a/src/Command/ImportCommand.php +++ b/src/Command/ImportCommand.php @@ -18,6 +18,7 @@ use Cake\Console\Arguments; use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; +use Cake\Core\Configure; use DatabaseBackup\Console\Command; use DatabaseBackup\Utility\BackupImport; use Exception; @@ -39,6 +40,10 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption ->addArgument('filename', [ 'help' => __d('database_backup', 'Filename. It can be an absolute path'), 'required' => true, + ]) + ->addOption('timeout', [ + 'help' => __d('database_backup', 'Timeout for shell commands. Default value: {0} seconds', Configure::readOrFail('DatabaseBackup.processTimeout')), + 'short' => 't', ]); } @@ -56,12 +61,15 @@ public function execute(Arguments $args, ConsoleIo $io): void try { $BackupImport = new BackupImport(); + $BackupImport->filename((string)$args->getArgument('filename')); - /** - * Imports - * @var string $file - */ + //Sets the timeout + if ($args->getOption('timeout')) { + $BackupImport->timeout((int)$args->getOption('timeout')); + } + + /** @var string $file */ $file = $BackupImport->import(); Exceptionist::isTrue($file, __d('database_backup', 'The `{0}` event stopped the operation', 'Backup.beforeImport')); $io->success(__d('database_backup', 'Backup `{0}` has been imported', rtr($file))); diff --git a/src/Console/Command.php b/src/Console/Command.php index d0b08cc3..45985fdf 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -38,6 +38,11 @@ public function execute(Arguments $args, ConsoleIo $io): void { $io->out(__d('database_backup', 'Connection: {0}', $this->getConnection()->config()['name'])); $io->out(__d('database_backup', 'Driver: {0}', $this->getDriverName())); + + if ($args->getOption('timeout')) { + $io->verbose(__d('database_backup', 'Timeout for shell commands: {0} seconds', $args->getOption('timeout'))); + } + $io->hr(); } } diff --git a/tests/TestCase/Command/ExportCommandTest.php b/tests/TestCase/Command/ExportCommandTest.php index 7e441516..95c4ff1a 100644 --- a/tests/TestCase/Command/ExportCommandTest.php +++ b/tests/TestCase/Command/ExportCommandTest.php @@ -46,11 +46,11 @@ public function testExecute(): void } /** - * Test for `execute()` method, with `compression` param + * Test for `execute()` method, with `compression` option * @test * @uses \DatabaseBackup\Command\ExportCommand::execute() */ - public function testExecuteCompressionParam(): void + public function testExecuteCompressionOption(): void { $this->exec($this->command . ' --compression bzip2'); $this->assertExitSuccess(); @@ -59,11 +59,11 @@ public function testExecuteCompressionParam(): void } /** - * Test for `execute()` method, with `filename` param + * Test for `execute()` method, with `filename` option * @test * @uses \DatabaseBackup\Command\ExportCommand::execute() */ - public function testExecuteFilenameParam(): void + public function testExecuteFilenameOption(): void { $this->exec($this->command . ' --filename backup.sql'); $this->assertExitSuccess(); @@ -72,11 +72,11 @@ public function testExecuteFilenameParam(): void } /** - * Test for `execute()` method, with `rotate` param + * Test for `execute()` method, with `rotate` option * @test * @uses \DatabaseBackup\Command\ExportCommand::execute() */ - public function testExecuteRotateParam(): void + public function testExecuteRotateOption(): void { $files = createSomeBackups(); $this->exec($this->command . ' --rotate 3 -v'); @@ -88,11 +88,11 @@ public function testExecuteRotateParam(): void } /** - * Test for `execute()` method, with `send` param + * Test for `execute()` method, with `send` option * @test * @uses \DatabaseBackup\Command\ExportCommand::execute() */ - public function testExecuteSendParam(): void + public function testExecuteSendOption(): void { $this->exec($this->command . ' --send mymail@example.com'); $this->assertExitSuccess(); @@ -100,4 +100,17 @@ public function testExecuteSendParam(): void $this->assertOutputRegExp('/Backup `[\w\-\/\:\\\\]+backup_[\w_]+\.sql` was sent via mail/'); $this->assertErrorEmpty(); } + + /** + * Test for `execute()` method, with `timeout` option + * @test + * @uses \DatabaseBackup\Command\ExportCommand::execute() + */ + public function testExecuteTimeoutOption(): void + { + $this->exec($this->command . ' --timeout 10'); + $this->assertExitSuccess(); + $this->assertOutputContains('Timeout for shell commands: 10 seconds'); + $this->assertErrorEmpty(); + } } diff --git a/tests/TestCase/Command/ImportCommandTest.php b/tests/TestCase/Command/ImportCommandTest.php index 1286bcc9..717e4949 100644 --- a/tests/TestCase/Command/ImportCommandTest.php +++ b/tests/TestCase/Command/ImportCommandTest.php @@ -22,6 +22,11 @@ */ class ImportCommandTest extends CommandTestCase { + /** + * @var string + */ + protected string $command = 'database_backup.import -v'; + /** * @test * @uses \DatabaseBackup\Command\ImportCommand::execute() @@ -29,7 +34,7 @@ class ImportCommandTest extends CommandTestCase public function testExecute(): void { $backup = createBackup(); - $this->exec('database_backup.import -v ' . $backup); + $this->exec($this->command . ' ' . $backup); $this->assertExitSuccess(); $this->assertOutputContains('Connection: test'); $this->assertOutputRegExp('/Driver: (Mysql|Postgres|Sqlite)/'); @@ -37,7 +42,21 @@ public function testExecute(): void $this->assertErrorEmpty(); //With a no existing file - $this->exec('database_backup.import -v /noExistingDir/backup.sql'); + $this->exec($this->command . ' /noExistingDir/backup.sql'); $this->assertExitError(); } + + /** + * Test for `execute()` method, with `timeout` option + * @test + * @uses \DatabaseBackup\Command\ImportCommand::execute() + */ + public function testExecuteTimeoutOption(): void + { + $backup = createBackup(); + $this->exec($this->command . ' --timeout 10 ' . $backup); + $this->assertExitSuccess(); + $this->assertOutputContains('Timeout for shell commands: 10 seconds'); + $this->assertErrorEmpty(); + } } From 03cdf3115683fc842c27812c7b71675d21f0edf4 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Tue, 6 Jun 2023 15:57:52 +0200 Subject: [PATCH 42/52] fixed tag --- src/Utility/AbstractBackupUtility.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index 7b2e6f51..772cf6c9 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -59,6 +59,7 @@ abstract public function filename(string $filename); * Sets the timeout for shell commands * @param int $timeout Timeout in seconds * @return $this + * @since 2.12.0 */ public function timeout(int $timeout) { From 1408330116b1abde9730f192f5f38b89d6f8f5aa Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Tue, 6 Jun 2023 16:10:06 +0200 Subject: [PATCH 43/52] updated pot template and italian translation --- resources/locales/database_backup.pot | 118 +++++++++++---------- resources/locales/it/database_backup.po | 130 +++++++++++++----------- 2 files changed, 139 insertions(+), 109 deletions(-) diff --git a/resources/locales/database_backup.pot b/resources/locales/database_backup.pot index 8d11b5c2..8ecb5e9f 100644 --- a/resources/locales/database_backup.pot +++ b/resources/locales/database_backup.pot @@ -4,7 +4,7 @@ #, fuzzy msgid "" msgstr "" -"POT-Creation-Date: 2019-12-18 16:44+0100\n" +"POT-Creation-Date: 2023-06-06 16:05+0200\n" "PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" "Last-Translator: NAME \n" "MIME-Version: 1.0\n" @@ -12,153 +12,169 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" -#: BackupTrait.php:56 -msgid "Binary for `{0}` could not be found. You have to set its path manually" -msgstr "" - -#: BackupTrait.php:104 -msgid "The `{0}` driver does not exist" -msgstr "" - -#: Command/DeleteAllCommand.php:34 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/DeleteAllCommand.php:36 msgid "Deletes all database backups" msgstr "" -#: Command/DeleteAllCommand.php:52 -#: Command/RotateCommand.php:62 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/DeleteAllCommand.php:53 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/RotateCommand.php:64 msgid "No backup has been deleted" msgstr "" -#: Command/DeleteAllCommand.php:58 -#: Command/RotateCommand.php:68 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/DeleteAllCommand.php:59 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/RotateCommand.php:70 msgid "Backup `{0}` has been deleted" msgstr "" -#: Command/DeleteAllCommand.php:61 -#: Command/RotateCommand.php:71 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/DeleteAllCommand.php:62 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/RotateCommand.php:73 msgid "Deleted backup files: {0}" msgstr "" -#: Command/ExportCommand.php:37 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:39 msgid "Exports a database backup" msgstr "" -#: Command/ExportCommand.php:41 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:43 msgid "Compression type. By default, no compression will be used" msgstr "" -#: Command/ExportCommand.php:45 -msgid "Filename. It can be an absolute path and may contain patterns. The compression type will be automatically setted" +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:47 +msgid "Filename. It can be an absolute path and may contain patterns. The compression type will be automatically set" msgstr "" -#: Command/ExportCommand.php:50 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:52 msgid "Rotates backups. You have to indicate the number of backups you want to keep. So, it will delete all backups that are older. By default, no backup will be deleted" msgstr "" -#: Command/ExportCommand.php:56 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:58 msgid "Sends the backup file via email. You have to indicate the recipient's email address" msgstr "" -#: Command/ExportCommand.php:94 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:63 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ImportCommand.php:45 +msgid "Timeout for shell commands. Default value: {0} seconds" +msgstr "" + +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:101 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ImportCommand.php:74 +msgid "The `{0}` event stopped the operation" +msgstr "" + +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:102 msgid "Backup `{0}` has been exported" msgstr "" -#: Command/ImportCommand.php:35 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ImportCommand.php:39 msgid "Imports a database backup" msgstr "" -#: Command/ImportCommand.php:37 -#: Command/SendCommand.php:38 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ImportCommand.php:41 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/SendCommand.php:40 msgid "Filename. It can be an absolute path" msgstr "" -#: Command/ImportCommand.php:57 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ImportCommand.php:75 msgid "Backup `{0}` has been imported" msgstr "" -#: Command/IndexCommand.php:36 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/IndexCommand.php:38 msgid "Lists database backups" msgstr "" -#: Command/IndexCommand.php:53 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/IndexCommand.php:54 msgid "Backup files found: {0}" msgstr "" -#: Command/IndexCommand.php:60 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/IndexCommand.php:60 msgid "Filename" msgstr "" -#: Command/IndexCommand.php:61 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/IndexCommand.php:61 msgid "Extension" msgstr "" -#: Command/IndexCommand.php:62 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/IndexCommand.php:62 msgid "Compression" msgstr "" -#: Command/IndexCommand.php:63 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/IndexCommand.php:63 msgid "Size" msgstr "" -#: Command/IndexCommand.php:64 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/IndexCommand.php:64 msgid "Datetime" msgstr "" -#: Command/RotateCommand.php:35 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/RotateCommand.php:37 msgid "Rotates backups" msgstr "" -#: Command/RotateCommand.php:37 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/RotateCommand.php:39 msgid "Number of backups you want to keep. So, it will delete all backups that are older" msgstr "" -#: Command/SendCommand.php:35 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/SendCommand.php:37 msgid "Send a database backup via mail" msgstr "" -#: Command/SendCommand.php:42 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/SendCommand.php:44 msgid "Recipient's email address" msgstr "" -#: Command/SendCommand.php:62 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/SendCommand.php:64 msgid "Backup `{0}` was sent via mail" msgstr "" -#: Console/Command.php:38 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Console/Command.php:39 msgid "Connection: {0}" msgstr "" -#: Console/Command.php:39 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Console/Command.php:40 msgid "Driver: {0}" msgstr "" -#: Driver/Driver.php:185 -#: Driver/Driver.php:228 -msgid "Failed with exit code `{0}`" +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Console/Command.php:43 +msgid "Timeout for shell commands: {0} seconds" msgstr "" -#: Utility/BackupExport.php:119 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/AbstractBackupUtility.php:83 +msgid "The `{0}` driver does not exist" +msgstr "" + +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupExport.php:75 msgid "Invalid compression type" msgstr "" -#: Utility/BackupExport.php:155 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupExport.php:106 msgid "File `{0}` already exists" msgstr "" -#: Utility/BackupExport.php:160 -#: Utility/BackupImport.php:66 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupExport.php:109 +msgid "Invalid `{0}` file extension" +msgstr "" + +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupExport.php:176 +msgid "Export failed with error message: `{0}`" +msgstr "" + +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupImport.php:38 msgid "Invalid file extension" msgstr "" -#: Utility/BackupImport.php:87 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupImport.php:59 msgid "You must first set the filename" msgstr "" -#: Utility/BackupManager.php:100 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupImport.php:73 +msgid "Import failed with error message: `{0}`" +msgstr "" + +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupManager.php:94 msgid "Invalid rotate value" msgstr "" -#: Utility/BackupManager.php:128 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupManager.php:117 msgid "Database backup {0} from {1}" msgstr "" diff --git a/resources/locales/it/database_backup.po b/resources/locales/it/database_backup.po index 80e1f808..77e1a307 100644 --- a/resources/locales/it/database_backup.po +++ b/resources/locales/it/database_backup.po @@ -3,60 +3,51 @@ # msgid "" msgstr "" -"POT-Creation-Date: 2019-12-18 16:44+0100\n" -"PO-Revision-Date: 2019-12-18 16:44+0100\n" +"POT-Creation-Date: 2023-06-06 16:05+0200\n" +"PO-Revision-Date: 2023-06-06 16:09+0200\n" "Last-Translator: Mirko Pagliai \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Language: it\n" +"Language: it_IT\n" -#: BackupTrait.php:56 -msgid "Binary for `{0}` could not be found. You have to set its path manually" -msgstr "" -"Il binario di `{0}` non è stato trovato. Devi indicare manualmente la sua path" - -#: BackupTrait.php:104 -msgid "The `{0}` driver does not exist" -msgstr "Il driver `{0}` non esiste" - -#: Command/DeleteAllCommand.php:34 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/DeleteAllCommand.php:36 msgid "Deletes all database backups" msgstr "Cancella tutti i backup del database" -#: Command/DeleteAllCommand.php:52 -#: Command/RotateCommand.php:62 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/DeleteAllCommand.php:53 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/RotateCommand.php:64 msgid "No backup has been deleted" msgstr "Nessun backup è stato cancellato" -#: Command/DeleteAllCommand.php:58 -#: Command/RotateCommand.php:68 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/DeleteAllCommand.php:59 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/RotateCommand.php:70 msgid "Backup `{0}` has been deleted" msgstr "Il backup `{0}` è stato cancellato" -#: Command/DeleteAllCommand.php:61 -#: Command/RotateCommand.php:71 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/DeleteAllCommand.php:62 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/RotateCommand.php:73 msgid "Deleted backup files: {0}" msgstr "File di backup cancellati: {0}" -#: Command/ExportCommand.php:37 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:39 msgid "Exports a database backup" msgstr "Esporta un backup del database" -#: Command/ExportCommand.php:41 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:43 msgid "Compression type. By default, no compression will be used" msgstr "Tipo di compressione. Di default, nessuna compressione sarà utilizzata" -#: Command/ExportCommand.php:45 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:47 msgid "" "Filename. It can be an absolute path and may contain patterns. The" -" compression type will be automatically setted" +" compression type will be automatically set" msgstr "" -"Filename. Può essere un percorso assoluto e può contenere pattern. Il tipo di" -" compressione verrà automaticamente impostato" +"Filename. Può essere una path assoluta e può contenere pattern. Il tipo di" +" compressione sarà impostato automaticamente" -#: Command/ExportCommand.php:50 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:52 msgid "" "Rotates backups. You have to indicate the number of backups you want to keep." " So, it will delete all backups that are older. By default, no backup will be" @@ -66,63 +57,73 @@ msgstr "" " cancellerà tutti i backup più vecchi. Di default, nessun backup verrà" " cancellato" -#: Command/ExportCommand.php:56 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:58 msgid "" "Sends the backup file via email. You have to indicate the recipient's email" " address" msgstr "" "Invia il backup via mail. Devi indicare l'indirizzo email del destinatario" -#: Command/ExportCommand.php:94 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:63 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ImportCommand.php:45 +msgid "Timeout for shell commands. Default value: {0} seconds" +msgstr "Timeout per i comandi della shell. Valore di default: {0} secondi" + +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:101 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ImportCommand.php:74 +msgid "The `{0}` event stopped the operation" +msgstr "L'evento `{0}` ha stoppato l'operazione" + +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ExportCommand.php:102 msgid "Backup `{0}` has been exported" msgstr "Il backup `{0}` è stato esportato" -#: Command/ImportCommand.php:35 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ImportCommand.php:39 msgid "Imports a database backup" msgstr "Importa un backup del database" -#: Command/ImportCommand.php:37 -#: Command/SendCommand.php:38 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ImportCommand.php:41 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/SendCommand.php:40 msgid "Filename. It can be an absolute path" msgstr "Filename. Può essere un percorso assoluto" -#: Command/ImportCommand.php:57 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/ImportCommand.php:75 msgid "Backup `{0}` has been imported" msgstr "Il backup `{0}` è stato importato" -#: Command/IndexCommand.php:36 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/IndexCommand.php:38 msgid "Lists database backups" msgstr "Elenca i backup del database" -#: Command/IndexCommand.php:53 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/IndexCommand.php:54 msgid "Backup files found: {0}" msgstr "File di backup trovati: {0}" -#: Command/IndexCommand.php:60 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/IndexCommand.php:60 msgid "Filename" msgstr "Filename" -#: Command/IndexCommand.php:61 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/IndexCommand.php:61 msgid "Extension" msgstr "Estensione" -#: Command/IndexCommand.php:62 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/IndexCommand.php:62 msgid "Compression" msgstr "Compressione" -#: Command/IndexCommand.php:63 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/IndexCommand.php:63 msgid "Size" msgstr "Dimensione" -#: Command/IndexCommand.php:64 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/IndexCommand.php:64 msgid "Datetime" msgstr "Data e orario" -#: Command/RotateCommand.php:35 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/RotateCommand.php:37 msgid "Rotates backups" msgstr "Ruota i backup" -#: Command/RotateCommand.php:37 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/RotateCommand.php:39 msgid "" "Number of backups you want to keep. So, it will delete all backups that are" " older" @@ -130,54 +131,67 @@ msgstr "" "Numero di backup che vuoi mantenere. Quindi, cancellerà tutti i backup più" " vecchi" -#: Command/SendCommand.php:35 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/SendCommand.php:37 msgid "Send a database backup via mail" msgstr "Invia un backup del database tramite mail" -#: Command/SendCommand.php:42 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/SendCommand.php:44 msgid "Recipient's email address" msgstr "Indirizzo email del destinatario" -#: Command/SendCommand.php:62 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Command/SendCommand.php:64 msgid "Backup `{0}` was sent via mail" msgstr "Il backup `{0}` è stato inviato tramite mail" -#: Console/Command.php:38 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Console/Command.php:39 msgid "Connection: {0}" msgstr "Connessione: {0}" -#: Console/Command.php:39 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Console/Command.php:40 msgid "Driver: {0}" msgstr "Driver: {0}" -#: Driver/Driver.php:185 -#: Driver/Driver.php:228 -msgid "Failed with exit code `{0}`" -msgstr "Fallito con codice di uscita `{0}`" +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Console/Command.php:43 +msgid "Timeout for shell commands: {0} seconds" +msgstr "Timeout per i comandi della shell: {0} secondi" -#: Utility/BackupExport.php:119 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/AbstractBackupUtility.php:83 +msgid "The `{0}` driver does not exist" +msgstr "Il driver `{0}` non esiste" + +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupExport.php:75 msgid "Invalid compression type" msgstr "Tipo di compressione non valido" -#: Utility/BackupExport.php:155 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupExport.php:106 msgid "File `{0}` already exists" msgstr "Il file `{0}` già esiste" -#: Utility/BackupExport.php:160 -#: Utility/BackupImport.php:66 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupExport.php:109 +msgid "Invalid `{0}` file extension" +msgstr "Estensione file `{0}` non valida" + +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupExport.php:176 +msgid "Export failed with error message: `{0}`" +msgstr "Esportazione fallita con messaggio di errore: `{0}`" + +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupImport.php:38 msgid "Invalid file extension" msgstr "Estensione del file non valida" -#: Utility/BackupImport.php:87 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupImport.php:59 msgid "You must first set the filename" msgstr "Devi prima impostare il filename" -#: Utility/BackupManager.php:100 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupImport.php:73 +msgid "Import failed with error message: `{0}`" +msgstr "Importazione fallita con messaggio di errore: `{0}`" + +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupManager.php:94 msgid "Invalid rotate value" msgstr "Valore rotazione non valido" -#: Utility/BackupManager.php:128 +#: ./home/mirko/Libs/Plugins/cakephp-database-backup/src/Utility/BackupManager.php:117 msgid "Database backup {0} from {1}" msgstr "Backup del database {0} da {1}" - From 8bfda48b7cc7c7f92f196c3a96987e86242b9d71 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Tue, 6 Jun 2023 16:19:16 +0200 Subject: [PATCH 44/52] updated --- psalm-baseline.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index c5f2e626..547198e0 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -12,6 +12,10 @@ + + $this->timeout + Configure::readOrFail('DatabaseBackup.processTimeout') + empty($this->Driver) From 5f93fab7dc9cc04cf8bf539cddeffcbb4bc987b4 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Tue, 6 Jun 2023 18:17:54 +0200 Subject: [PATCH 45/52] fixed --- config/bootstrap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/bootstrap.php b/config/bootstrap.php index 398ea81e..984bd139 100644 --- a/config/bootstrap.php +++ b/config/bootstrap.php @@ -38,8 +38,8 @@ //Writes default configuration values $defaults = [ - 'DatabaseBackup.connection' => 'default', 'DatabaseBackup.chmod' => 0664, + 'DatabaseBackup.connection' => 'default', 'DatabaseBackup.processTimeout' => 60, 'DatabaseBackup.target' => ROOT . 'backups', 'DatabaseBackup.mysql.export' => '{{BINARY}} --defaults-file={{AUTH_FILE}} {{DB_NAME}}', From f48559b9bc12c13eba7b8cde7171be3bc1bafd0b Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Tue, 6 Jun 2023 18:18:03 +0200 Subject: [PATCH 46/52] fixed `@see` tags --- src/Command/DeleteAllCommand.php | 2 +- src/Command/ExportCommand.php | 2 +- src/Command/ImportCommand.php | 2 +- src/Command/IndexCommand.php | 2 +- src/Command/RotateCommand.php | 2 +- src/Command/SendCommand.php | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Command/DeleteAllCommand.php b/src/Command/DeleteAllCommand.php index 49953f5d..5eadb344 100644 --- a/src/Command/DeleteAllCommand.php +++ b/src/Command/DeleteAllCommand.php @@ -23,6 +23,7 @@ /** * Deletes all backup files + * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-commands#delete_all */ class DeleteAllCommand extends Command { @@ -42,7 +43,6 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption * @param \Cake\Console\ConsoleIo $io The console io * @return void * @throws \ErrorException|\ReflectionException - * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-the-BackupShell#delete_all */ public function execute(Arguments $args, ConsoleIo $io): void { diff --git a/src/Command/ExportCommand.php b/src/Command/ExportCommand.php index d4a747e9..3737df7c 100644 --- a/src/Command/ExportCommand.php +++ b/src/Command/ExportCommand.php @@ -26,6 +26,7 @@ /** * Exports a database backup + * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-commands#export */ class ExportCommand extends Command { @@ -75,7 +76,6 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption * @return void * @throws \Cake\Console\Exception\StopException * @throws \ReflectionException - * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-the-BackupShell#export */ public function execute(Arguments $args, ConsoleIo $io): void { diff --git a/src/Command/ImportCommand.php b/src/Command/ImportCommand.php index 08580139..8c061b7d 100644 --- a/src/Command/ImportCommand.php +++ b/src/Command/ImportCommand.php @@ -26,6 +26,7 @@ /** * Imports a database backup + * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-commands#import */ class ImportCommand extends Command { @@ -52,7 +53,6 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption * @param \Cake\Console\Arguments $args The command arguments * @param \Cake\Console\ConsoleIo $io The console io * @return void - * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-the-BackupShell#import * @throws \Cake\Console\Exception\StopException|\ReflectionException */ public function execute(Arguments $args, ConsoleIo $io): void diff --git a/src/Command/IndexCommand.php b/src/Command/IndexCommand.php index b603efc6..7c522098 100644 --- a/src/Command/IndexCommand.php +++ b/src/Command/IndexCommand.php @@ -25,6 +25,7 @@ /** * Lists database backups + * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-commands#index */ class IndexCommand extends Command { @@ -44,7 +45,6 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption * @param \Cake\Console\ConsoleIo $io The console io * @return void * @throws \ReflectionException - * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-the-BackupShell#index */ public function execute(Arguments $args, ConsoleIo $io): void { diff --git a/src/Command/RotateCommand.php b/src/Command/RotateCommand.php index a407b786..1dbf1288 100644 --- a/src/Command/RotateCommand.php +++ b/src/Command/RotateCommand.php @@ -24,6 +24,7 @@ /** * Rotates backups + * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-commands#rotate */ class RotateCommand extends Command { @@ -49,7 +50,6 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption * @param \Cake\Console\Arguments $args The command arguments * @param \Cake\Console\ConsoleIo $io The console io * @return void - * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-the-BackupShell#rotate * @throws \Cake\Console\Exception\StopException|\ReflectionException */ public function execute(Arguments $args, ConsoleIo $io): void diff --git a/src/Command/SendCommand.php b/src/Command/SendCommand.php index d733c413..f774ddfe 100644 --- a/src/Command/SendCommand.php +++ b/src/Command/SendCommand.php @@ -24,6 +24,7 @@ /** * Sends a backup file via email + * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-commands#send */ class SendCommand extends Command { @@ -52,7 +53,6 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption * @param \Cake\Console\Arguments $args The command arguments * @param \Cake\Console\ConsoleIo $io The console io * @return void - * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-the-BackupShell#send * @throws \Cake\Console\Exception\StopException|\ReflectionException */ public function execute(Arguments $args, ConsoleIo $io): void From 504e0282a1ce4566eb826f5fcc0f690d5f6fe94e Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Tue, 6 Jun 2023 19:14:25 +0200 Subject: [PATCH 47/52] added `AbstractBackupUtility::__get()` magic method for reading `BackupExport`/`BackupImport` properties --- CHANGELOG.md | 3 +- phpstan-baseline.neon | 10 ++++++ psalm-baseline.xml | 10 ------ src/Utility/AbstractBackupUtility.php | 15 +++++++- src/Utility/BackupExport.php | 6 +++- .../Utility/BackupExportAndImportTest.php | 30 ++++++++++++++-- tests/TestCase/Utility/BackupExportTest.php | 34 +++++++++---------- tests/TestCase/Utility/BackupImportTest.php | 9 ++--- 8 files changed, 78 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 410824d2..33daf0a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ * the events (`Backup.beforeExport`, `Backup.afterExport`, `Backup.beforeImport`, `Backup.afterImport`, which remain implemented by the driver classes) are directly dispatched by the `BackupExport::export()` and `BackupImport::import()` methods, and no longer by the drivers themselves; -* added the `AbstractBackupUtility` abstract class that provides the code common to `BackupExport` and `BackupImport`; +* added the `AbstractBackupUtility` abstract class that provides the code common to `BackupExport` and `BackupImport`, + with the new `AbstractBackupUtility::__get()` magic method for reading `BackupExport`/`BackupImport` properties; * removed `$Driver` public property for `BackupExport`/`BackupImport` and added `AbstractBackupUtility::getDriver()` method; * `Driver::_exec()` method has become `AbstractBackupUtility::getProcess()`; * `BackupTrait::getDriver()` method has become `AbstractBackupUtility::getDriver()`; diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index d6e2ba64..232acd18 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -5,3 +5,13 @@ parameters: count: 1 path: tests/TestCase/BackupTraitTest.php + - + message: "#^Access to an undefined property DatabaseBackup\\\\Utility\\\\BackupExport\\:\\:\\$noExistingProperty\\.$#" + count: 1 + path: tests/TestCase/Utility/BackupExportAndImportTest.php + + - + message: "#^Expression \"\\$this\\-\\>BackupExport\\-\\>noExistingProperty\" on a separate line does not do anything\\.$#" + count: 1 + path: tests/TestCase/Utility/BackupExportAndImportTest.php + diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 547198e0..749aa3fe 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -12,20 +12,10 @@ - - $this->timeout - Configure::readOrFail('DatabaseBackup.processTimeout') - empty($this->Driver) - - - $this->defaultExtension - $this->extension - - \Cake\Collection\CollectionInterface<\Cake\ORM\Entity> diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index 772cf6c9..3d8958a4 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -26,6 +26,8 @@ * AbstractBackupUtility. * * Provides the code common to the `BackupExport` and `BackupImport` classes. + * @property string $filename + * @property int $timeout */ abstract class AbstractBackupUtility { @@ -46,7 +48,18 @@ abstract class AbstractBackupUtility /** * @var \DatabaseBackup\Driver\Driver */ - protected Driver $Driver; + private Driver $Driver; + + /** + * Magic method for reading data from inaccessible (protected or private) or non-existing properties + * @param string $name Property name + * @return mixed + * @since 2.12.0 + */ + public function __get(string $name) + { + return $this->$name; + } /** * Sets the filename diff --git a/src/Utility/BackupExport.php b/src/Utility/BackupExport.php index e579debf..ede5d105 100644 --- a/src/Utility/BackupExport.php +++ b/src/Utility/BackupExport.php @@ -21,6 +21,10 @@ /** * Utility to export databases + * @property ?string $compression + * @property ?string $emailRecipient + * @property string $extension + * @property int $rotate */ class BackupExport extends AbstractBackupUtility { @@ -34,7 +38,7 @@ class BackupExport extends AbstractBackupUtility * Default extension * @var string */ - protected string $defaultExtension = 'sql'; + private string $defaultExtension = 'sql'; /** * Recipient of the email, if you want to send the backup via mail diff --git a/tests/TestCase/Utility/BackupExportAndImportTest.php b/tests/TestCase/Utility/BackupExportAndImportTest.php index 4bdf319d..565fda96 100644 --- a/tests/TestCase/Utility/BackupExportAndImportTest.php +++ b/tests/TestCase/Utility/BackupExportAndImportTest.php @@ -20,6 +20,11 @@ use DatabaseBackup\Utility\BackupExport; use DatabaseBackup\Utility\BackupImport; +/** + * BackupExportAndImportTest class. + * + * Performs tests common to the `BackupExport` and `BackupImport` classes. + */ class BackupExportAndImportTest extends TestCase { /** @@ -27,6 +32,11 @@ class BackupExportAndImportTest extends TestCase */ protected Table $Articles; + /** + * @var \DatabaseBackup\Utility\BackupExport + */ + protected BackupExport $BackupExport; + /** * @var \Cake\ORM\Table */ @@ -58,6 +68,8 @@ public function setUp(): void { parent::setUp(); + $this->BackupExport ??= new BackupExport(); + /** @var \Cake\Database\Connection $connection */ $connection = $this->getConnection('test'); foreach (['Articles', 'Comments'] as $name) { @@ -65,14 +77,28 @@ public function setUp(): void } } + /** + * @test + * @uses \DatabaseBackup\Utility\AbstractBackupUtility::__get() + */ + public function testGetMagicMethod(): void + { + $this->assertNotEmpty($this->BackupExport->rotate); + + //With a no existing property + $this->expectWarning(); + $this->expectExceptionMessage('Undefined property: ' . get_class($this->BackupExport) . '::$noExistingProperty'); + $this->BackupExport->noExistingProperty; + } + /** * Test for `export()` and `import()` methods. It tests that the backup is properly exported and then imported + * @test * @uses \DatabaseBackup\Utility\BackupExport::export() * @uses \DatabaseBackup\Utility\BackupImport::import() */ public function testExportAndImport(): void { - $BackupExport = new BackupExport(); $BackupImport = new BackupImport(); foreach (array_keys(DATABASE_BACKUP_EXTENSIONS) as $extension) { @@ -84,7 +110,7 @@ public function testExportAndImport(): void $this->assertCount(6, $initial['Comments']); //Exports backup and deletes article with ID 2 and comment with ID 4 - $result = $BackupExport->filename($expectedFilename)->export(); + $result = $this->BackupExport->filename($expectedFilename)->export(); $this->assertSame($expectedFilename, $result); $this->Articles->delete($this->Articles->get(2), ['atomic' => false]); $this->Comments->delete($this->Comments->get(4), ['atomic' => false]); diff --git a/tests/TestCase/Utility/BackupExportTest.php b/tests/TestCase/Utility/BackupExportTest.php index b2dbe469..00e6ea21 100644 --- a/tests/TestCase/Utility/BackupExportTest.php +++ b/tests/TestCase/Utility/BackupExportTest.php @@ -23,7 +23,6 @@ use DatabaseBackup\Utility\BackupExport; use Symfony\Component\Process\Exception\ProcessTimedOutException; use Symfony\Component\Process\Process; -use Tools\TestSuite\ReflectionTrait; /** * BackupExportTest class @@ -31,7 +30,6 @@ class BackupExportTest extends TestCase { use EmailTrait; - use ReflectionTrait; /** * @var \DatabaseBackup\Utility\BackupExport @@ -58,8 +56,8 @@ public function setUp(): void public function testCompression(): void { $this->BackupExport->compression('bzip2'); - $this->assertSame('bzip2', $this->getProperty($this->BackupExport, 'compression')); - $this->assertSame('sql.bz2', $this->getProperty($this->BackupExport, 'extension')); + $this->assertSame('bzip2', $this->BackupExport->compression); + $this->assertSame('sql.bz2', $this->BackupExport->extension); //With an invalid type $this->expectExceptionMessage('Invalid compression type'); @@ -74,31 +72,31 @@ public function testCompression(): void public function testFilename(): void { $this->BackupExport->filename('backup.sql.bz2'); - $this->assertSame(Configure::read('DatabaseBackup.target') . 'backup.sql.bz2', $this->getProperty($this->BackupExport, 'filename')); - $this->assertSame('bzip2', $this->getProperty($this->BackupExport, 'compression')); - $this->assertSame('sql.bz2', $this->getProperty($this->BackupExport, 'extension')); + $this->assertSame(Configure::read('DatabaseBackup.target') . 'backup.sql.bz2', $this->BackupExport->filename); + $this->assertSame('bzip2', $this->BackupExport->compression); + $this->assertSame('sql.bz2', $this->BackupExport->extension); //Compression is ignored, because there's a filename $this->BackupExport->compression('gzip')->filename('backup.sql.bz2'); - $this->assertSame('backup.sql.bz2', basename($this->getProperty($this->BackupExport, 'filename'))); - $this->assertSame('bzip2', $this->getProperty($this->BackupExport, 'compression')); - $this->assertSame('sql.bz2', $this->getProperty($this->BackupExport, 'extension')); + $this->assertSame('backup.sql.bz2', basename($this->BackupExport->filename)); + $this->assertSame('bzip2', $this->BackupExport->compression); + $this->assertSame('sql.bz2', $this->BackupExport->extension); //Filename with `{$DATABASE}` pattern $this->BackupExport->filename('{$DATABASE}.sql'); - $this->assertSame('test.sql', basename($this->getProperty($this->BackupExport, 'filename'))); + $this->assertSame('test.sql', basename($this->BackupExport->filename)); //Filename with `{$DATETIME}` pattern $this->BackupExport->filename('{$DATETIME}.sql'); - $this->assertMatchesRegularExpression('/^\d{14}\.sql$/', basename($this->getProperty($this->BackupExport, 'filename'))); + $this->assertMatchesRegularExpression('/^\d{14}\.sql$/', basename($this->BackupExport->filename)); //Filename with `{$HOSTNAME}` pattern $this->BackupExport->filename('{$HOSTNAME}.sql'); - $this->assertSame('localhost.sql', basename($this->getProperty($this->BackupExport, 'filename'))); + $this->assertSame('localhost.sql', basename($this->BackupExport->filename)); //Filename with `{$TIMESTAMP}` pattern $this->BackupExport->filename('{$TIMESTAMP}.sql'); - $this->assertMatchesRegularExpression('/^\d{10}\.sql$/', basename($this->getProperty($this->BackupExport, 'filename'))); + $this->assertMatchesRegularExpression('/^\d{10}\.sql$/', basename($this->BackupExport->filename)); //With invalid extension $this->expectExceptionMessage('Invalid `txt` file extension'); @@ -112,7 +110,7 @@ public function testFilename(): void public function testRotate(): void { $this->BackupExport->rotate(10); - $this->assertSame(10, $this->getProperty($this->BackupExport, 'rotate')); + $this->assertSame(10, $this->BackupExport->rotate); $this->expectExceptionMessage('Invalid rotate value'); $this->BackupExport->rotate(-1)->export(); @@ -125,11 +123,11 @@ public function testRotate(): void public function testSend(): void { $this->BackupExport->send(); - $this->assertNull($this->getProperty($this->BackupExport, 'emailRecipient')); + $this->assertNull($this->BackupExport->emailRecipient); $recipient = 'recipient@example.com'; $this->BackupExport->send($recipient); - $this->assertSame($recipient, $this->getProperty($this->BackupExport, 'emailRecipient')); + $this->assertSame($recipient, $this->BackupExport->emailRecipient); } /** @@ -139,7 +137,7 @@ public function testSend(): void public function testTimeout(): void { $this->BackupExport->timeout(120); - $this->assertSame(120, $this->getProperty($this->BackupExport, 'timeout')); + $this->assertSame(120, $this->BackupExport->timeout); } /** diff --git a/tests/TestCase/Utility/BackupImportTest.php b/tests/TestCase/Utility/BackupImportTest.php index 612c0e00..d0fffdfd 100644 --- a/tests/TestCase/Utility/BackupImportTest.php +++ b/tests/TestCase/Utility/BackupImportTest.php @@ -23,15 +23,12 @@ use Symfony\Component\Process\Process; use Tools\Exception\NotReadableException; use Tools\Filesystem; -use Tools\TestSuite\ReflectionTrait; /** * BackupImportTest class */ class BackupImportTest extends TestCase { - use ReflectionTrait; - /** * @var \DatabaseBackup\Utility\BackupImport */ @@ -59,13 +56,13 @@ public function testFilename(): void foreach (array_keys(DATABASE_BACKUP_EXTENSIONS) as $extension) { $result = createBackup('backup.' . $extension); $this->BackupImport->filename($result); - $this->assertSame($result, $this->getProperty($this->BackupImport, 'filename')); + $this->assertSame($result, $this->BackupImport->filename); } //With a relative path $result = createBackup('backup_' . time() . '.sql'); $this->BackupImport->filename(basename($result)); - $this->assertSame($result, $this->getProperty($this->BackupImport, 'filename')); + $this->assertSame($result, $this->BackupImport->filename); //With an invalid directory $this->expectException(NotReadableException::class); @@ -84,7 +81,7 @@ public function testFilename(): void public function testTimeout(): void { $this->BackupImport->timeout(120); - $this->assertSame(120, $this->getProperty($this->BackupImport, 'timeout')); + $this->assertSame(120, $this->BackupImport->timeout); } /** From 75ce98fcd9d8d7cac97f4512fc52a0bf6d4a2e87 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Tue, 6 Jun 2023 19:20:35 +0200 Subject: [PATCH 48/52] last fixes --- src/TestSuite/DriverTestCase.php | 2 +- src/Utility/AbstractBackupUtility.php | 2 ++ src/Utility/BackupExport.php | 7 +++++-- src/Utility/BackupImport.php | 4 ++-- src/Utility/BackupManager.php | 1 + 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/TestSuite/DriverTestCase.php b/src/TestSuite/DriverTestCase.php index e4ff66fb..0484a0df 100644 --- a/src/TestSuite/DriverTestCase.php +++ b/src/TestSuite/DriverTestCase.php @@ -1,5 +1,5 @@ Array of deleted files * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-the-BackupManager-utility#rotate * @throws \ErrorException + * @noinspection PhpDocRedundantThrowsInspection */ public static function rotate(int $rotate): array { From 87711e5cfdbeb9aa1358ed26fbeb59ffb8d66c4d Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Tue, 6 Jun 2023 19:34:33 +0200 Subject: [PATCH 49/52] the abstract `Driver` class has become `AbstractDriver` --- CHANGELOG.md | 8 ++++---- src/Driver/{Driver.php => AbstractDriver.php} | 2 +- src/Driver/Mysql.php | 2 +- src/Driver/Postgres.php | 2 +- src/Driver/Sqlite.php | 2 +- src/TestSuite/DriverTestCase.php | 12 ++++++------ src/Utility/AbstractBackupUtility.php | 14 +++++++------- src/Utility/BackupExport.php | 4 ++-- src/Utility/BackupImport.php | 4 ++-- tests/TestCase/Driver/MysqlTest.php | 4 ++-- .../TestCase/Utility/BackupExportAndImportTest.php | 2 +- 11 files changed, 28 insertions(+), 28 deletions(-) rename src/Driver/{Driver.php => AbstractDriver.php} (98%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33daf0a4..a57eb1b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,19 +9,19 @@ * added the `AbstractBackupUtility` abstract class that provides the code common to `BackupExport` and `BackupImport`, with the new `AbstractBackupUtility::__get()` magic method for reading `BackupExport`/`BackupImport` properties; * removed `$Driver` public property for `BackupExport`/`BackupImport` and added `AbstractBackupUtility::getDriver()` method; -* `Driver::_exec()` method has become `AbstractBackupUtility::getProcess()`; +* the abstract `Driver` class has become `AbstractDriver` and no longer takes a connection as constructor argument, but + directly uses the one set by the configuration. The old `Driver::_exec()` method has been moved and has become + `AbstractBackupUtility::getProcess()`. The old `Driver::export()` and `Driver::import()` methods no longer exist and + their code has been "absorbed" into the `BackupExport::export()` and `BackupImport::import()` methods; * `BackupTrait::getDriver()` method has become `AbstractBackupUtility::getDriver()`; * `BackupTrait::getDriverName()` and `AbstractBackupUtility::getDriver()` no longer accept a connection as argument, but directly use the one set by the configuration; -* the `Driver` class no longer accepts a connection as constructor argument, but directly uses the one set by the configuration; * the `BackupExport::export()` and `BackupImport::import()` methods can return the filename path on success or `false` if the `Backup.beforeExport`/`Backup.beforeImport` events are stopped; * `Driver::_getExecutable()`, `Driver::_getExportExecutable()` and `Driver::_getImportExecutable()` have become `Driver::getExecutable()`, `Driver::getExportExecutable()` and `Driver::getImportExecutable()`; * the `Driver::getConfig()` method no longer accepts `null` as argument, but only a string as key, since there is no need to return the whole configuration; -* the code of `Driver::export()` and `Driver::import()` methods has been absorbed by `BackupExport::export()` and - `BackupImport::import()` and therefore those methods no longer exist; * `MySql::getAuthFile()` method has become `getAuthFilePath()`, to be more understandable; * `MySql::deleteAuthFile()` method returns void (there is no need for it to return anything); * removed useless `TestCase::getMockForAbstractDriver()` method; diff --git a/src/Driver/Driver.php b/src/Driver/AbstractDriver.php similarity index 98% rename from src/Driver/Driver.php rename to src/Driver/AbstractDriver.php index 7125de30..9f17551f 100644 --- a/src/Driver/Driver.php +++ b/src/Driver/AbstractDriver.php @@ -25,7 +25,7 @@ * Represents a driver containing all methods to export/import database backups according to the connection * @method \Cake\Event\EventManager getEventManager() */ -abstract class Driver implements EventListenerInterface +abstract class AbstractDriver implements EventListenerInterface { use BackupTrait; use EventDispatcherTrait; diff --git a/src/Driver/Mysql.php b/src/Driver/Mysql.php index 9f4ffa1d..eb7972c1 100644 --- a/src/Driver/Mysql.php +++ b/src/Driver/Mysql.php @@ -20,7 +20,7 @@ /** * Mysql driver to export/import database backups */ -class Mysql extends Driver +class Mysql extends AbstractDriver { /** * @since 2.1.0 diff --git a/src/Driver/Postgres.php b/src/Driver/Postgres.php index 35a857e5..6642636e 100644 --- a/src/Driver/Postgres.php +++ b/src/Driver/Postgres.php @@ -18,6 +18,6 @@ /** * Postgres driver to export/import database backups */ -class Postgres extends Driver +class Postgres extends AbstractDriver { } diff --git a/src/Driver/Sqlite.php b/src/Driver/Sqlite.php index 939cfe1b..ed0fc56a 100644 --- a/src/Driver/Sqlite.php +++ b/src/Driver/Sqlite.php @@ -18,7 +18,7 @@ /** * Sqlite driver to export/import database backups */ -class Sqlite extends Driver +class Sqlite extends AbstractDriver { /** * Called before import diff --git a/src/TestSuite/DriverTestCase.php b/src/TestSuite/DriverTestCase.php index 0484a0df..94a78660 100644 --- a/src/TestSuite/DriverTestCase.php +++ b/src/TestSuite/DriverTestCase.php @@ -17,7 +17,7 @@ namespace DatabaseBackup\TestSuite; use Cake\Core\App; -use DatabaseBackup\Driver\Driver; +use DatabaseBackup\Driver\AbstractDriver; /** * DriverTestCase class. @@ -27,9 +27,9 @@ abstract class DriverTestCase extends TestCase { /** - * @var \DatabaseBackup\Driver\Driver + * @var \DatabaseBackup\Driver\AbstractDriver */ - protected Driver $Driver; + protected AbstractDriver $Driver; /** * Called before every test method @@ -40,7 +40,7 @@ public function setUp(): void parent::setUp(); if (empty($this->Driver)) { - /** @var class-string<\DatabaseBackup\Driver\Driver> $DriverClass */ + /** @var class-string<\DatabaseBackup\Driver\AbstractDriver> $DriverClass */ $DriverClass = App::className('DatabaseBackup.' . $this->getDriverName(), 'Driver'); $this->Driver = new $DriverClass(); } @@ -51,7 +51,7 @@ public function setUp(): void /** * @return void * @throws \ReflectionException|\ErrorException - * @uses \DatabaseBackup\Driver\Driver::getExportExecutable() + * @uses \DatabaseBackup\Driver\AbstractDriver::getExportExecutable() */ public function testGetExportExecutable(): void { @@ -69,7 +69,7 @@ public function testGetExportExecutable(): void /** * @return void * @throws \ReflectionException|\ErrorException - * @uses \DatabaseBackup\Driver\Driver::getImportExecutable() + * @uses \DatabaseBackup\Driver\AbstractDriver::getImportExecutable() */ public function testGetImportExecutable(): void { diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index d04896ee..0e6afee3 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -18,7 +18,7 @@ use Cake\Core\App; use Cake\Core\Configure; use DatabaseBackup\BackupTrait; -use DatabaseBackup\Driver\Driver; +use DatabaseBackup\Driver\AbstractDriver; use Symfony\Component\Process\Process; use Tools\Exceptionist; @@ -46,9 +46,9 @@ abstract class AbstractBackupUtility protected int $timeout; /** - * @var \DatabaseBackup\Driver\Driver + * @var \DatabaseBackup\Driver\AbstractDriver */ - private Driver $Driver; + private AbstractDriver $Driver; /** * Magic method for reading data from inaccessible (protected or private) or non-existing properties @@ -84,16 +84,16 @@ public function timeout(int $timeout) } /** - * Gets the `Driver` instance, containing all methods to export/import database backups - * @return \DatabaseBackup\Driver\Driver A `Driver` instance + * Gets the driver instance + * @return \DatabaseBackup\Driver\AbstractDriver A driver instance * @throws \ErrorException|\ReflectionException * @since 2.0.0 */ - public function getDriver(): Driver + public function getDriver(): AbstractDriver { if (empty($this->Driver)) { $name = $this->getDriverName(); - /** @var class-string<\DatabaseBackup\Driver\Driver> $className */ + /** @var class-string<\DatabaseBackup\Driver\AbstractDriver> $className */ $className = App::classname('DatabaseBackup.' . $name, 'Driver'); Exceptionist::isTrue($className, __d('database_backup', 'The `{0}` driver does not exist', $name)); diff --git a/src/Utility/BackupExport.php b/src/Utility/BackupExport.php index ce14c231..52f245cd 100644 --- a/src/Utility/BackupExport.php +++ b/src/Utility/BackupExport.php @@ -157,8 +157,8 @@ public function send(?string $recipient = null) * - `Backup.afterExport`: will be triggered after export. * @return string|false Filename path on success or `false` if the `Backup.beforeExport` event is stopped * @throws \Exception - * @see \DatabaseBackup\Driver\Driver::afterExport() - * @see \DatabaseBackup\Driver\Driver::beforeExport() + * @see \DatabaseBackup\Driver\AbstractDriver::afterExport() + * @see \DatabaseBackup\Driver\AbstractDriver::beforeExport() * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-the-BackupExport-utility#export */ public function export() diff --git a/src/Utility/BackupImport.php b/src/Utility/BackupImport.php index 350236cc..e9f5a107 100644 --- a/src/Utility/BackupImport.php +++ b/src/Utility/BackupImport.php @@ -50,8 +50,8 @@ public function filename(string $filename) * - `Backup.afterImport`: will be triggered after import. * @return string|false Filename path on success or `false` if the `Backup.beforeImport` event is stopped * @throws \ErrorException|\ReflectionException - * @see \DatabaseBackup\Driver\Driver::afterImport() - * @see \DatabaseBackup\Driver\Driver::beforeImport() + * @see \DatabaseBackup\Driver\AbstractDriver::afterImport() + * @see \DatabaseBackup\Driver\AbstractDriver::beforeImport() * @see https://github.com/mirko-pagliai/cakephp-database-backup/wiki/How-to-use-the-BackupImport-utility#import */ public function import() diff --git a/tests/TestCase/Driver/MysqlTest.php b/tests/TestCase/Driver/MysqlTest.php index 73a8a4ad..b65d9e93 100644 --- a/tests/TestCase/Driver/MysqlTest.php +++ b/tests/TestCase/Driver/MysqlTest.php @@ -15,7 +15,7 @@ */ namespace DatabaseBackup\Test\TestCase\Driver; -use DatabaseBackup\Driver\Driver; +use DatabaseBackup\Driver\AbstractDriver; use DatabaseBackup\Driver\Mysql; use DatabaseBackup\TestSuite\DriverTestCase; use Tools\Filesystem; @@ -28,7 +28,7 @@ class MysqlTest extends DriverTestCase /** * @var \DatabaseBackup\Driver\Mysql&\PHPUnit\Framework\MockObject\MockObject */ - protected Driver $Driver; + protected AbstractDriver $Driver; /** * Called before every test method diff --git a/tests/TestCase/Utility/BackupExportAndImportTest.php b/tests/TestCase/Utility/BackupExportAndImportTest.php index 565fda96..3818a1e4 100644 --- a/tests/TestCase/Utility/BackupExportAndImportTest.php +++ b/tests/TestCase/Utility/BackupExportAndImportTest.php @@ -83,7 +83,7 @@ public function setUp(): void */ public function testGetMagicMethod(): void { - $this->assertNotEmpty($this->BackupExport->rotate); + $this->assertNull($this->BackupExport->emailRecipient); //With a no existing property $this->expectWarning(); From 8fefc55f801dbad7fae5bc1d5cfb18f4736b01f1 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Tue, 6 Jun 2023 19:36:37 +0200 Subject: [PATCH 50/52] fixed --- tests/TestCase/Utility/BackupExportAndImportTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/TestCase/Utility/BackupExportAndImportTest.php b/tests/TestCase/Utility/BackupExportAndImportTest.php index 3818a1e4..2f29dbc4 100644 --- a/tests/TestCase/Utility/BackupExportAndImportTest.php +++ b/tests/TestCase/Utility/BackupExportAndImportTest.php @@ -86,7 +86,6 @@ public function testGetMagicMethod(): void $this->assertNull($this->BackupExport->emailRecipient); //With a no existing property - $this->expectWarning(); $this->expectExceptionMessage('Undefined property: ' . get_class($this->BackupExport) . '::$noExistingProperty'); $this->BackupExport->noExistingProperty; } From e5b53a7ec08c8c09627ed0ea6cb0c57170edbba9 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Tue, 6 Jun 2023 19:44:01 +0200 Subject: [PATCH 51/52] fixed --- src/Utility/AbstractBackupUtility.php | 6 ++++++ tests/TestCase/Utility/BackupExportAndImportTest.php | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index 0e6afee3..4c26c808 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -19,6 +19,7 @@ use Cake\Core\Configure; use DatabaseBackup\BackupTrait; use DatabaseBackup\Driver\AbstractDriver; +use LogicException; use Symfony\Component\Process\Process; use Tools\Exceptionist; @@ -55,9 +56,14 @@ abstract class AbstractBackupUtility * @param string $name Property name * @return mixed * @since 2.12.0 + * @throw \LogicException */ public function __get(string $name) { + if (!property_exists($this, $name)) { + throw new LogicException('Undefined property: ' . get_class($this) . '::$' . $name); + } + return $this->$name; } diff --git a/tests/TestCase/Utility/BackupExportAndImportTest.php b/tests/TestCase/Utility/BackupExportAndImportTest.php index 2f29dbc4..849cda49 100644 --- a/tests/TestCase/Utility/BackupExportAndImportTest.php +++ b/tests/TestCase/Utility/BackupExportAndImportTest.php @@ -85,7 +85,6 @@ public function testGetMagicMethod(): void { $this->assertNull($this->BackupExport->emailRecipient); - //With a no existing property $this->expectExceptionMessage('Undefined property: ' . get_class($this->BackupExport) . '::$noExistingProperty'); $this->BackupExport->noExistingProperty; } From c2ce2109f7238b97ea47066e6573c13e55a72c88 Mon Sep 17 00:00:00 2001 From: mirko-pagliai Date: Tue, 6 Jun 2023 19:49:45 +0200 Subject: [PATCH 52/52] fixed for sniffer --- src/Utility/AbstractBackupUtility.php | 3 ++- tests/TestCase/Utility/BackupExportAndImportTest.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Utility/AbstractBackupUtility.php b/src/Utility/AbstractBackupUtility.php index 4c26c808..4e079be9 100644 --- a/src/Utility/AbstractBackupUtility.php +++ b/src/Utility/AbstractBackupUtility.php @@ -61,7 +61,8 @@ abstract class AbstractBackupUtility public function __get(string $name) { if (!property_exists($this, $name)) { - throw new LogicException('Undefined property: ' . get_class($this) . '::$' . $name); + $class = &$this; + throw new LogicException('Undefined property: ' . get_class($class) . '::$' . $name); } return $this->$name; diff --git a/tests/TestCase/Utility/BackupExportAndImportTest.php b/tests/TestCase/Utility/BackupExportAndImportTest.php index 849cda49..eab7ec96 100644 --- a/tests/TestCase/Utility/BackupExportAndImportTest.php +++ b/tests/TestCase/Utility/BackupExportAndImportTest.php @@ -85,7 +85,7 @@ public function testGetMagicMethod(): void { $this->assertNull($this->BackupExport->emailRecipient); - $this->expectExceptionMessage('Undefined property: ' . get_class($this->BackupExport) . '::$noExistingProperty'); + $this->expectExceptionMessage('Undefined property: ' . BackupExport::class . '::$noExistingProperty'); $this->BackupExport->noExistingProperty; }