diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c09c191..e35eaa1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,16 @@ # 2.x branch +## 2.10 branch +### 2.10.0-beta1 +* now allows to configure and customize via bootstrap the executable commands to + import and export databases, for each driver, with placeholders; +* `__exportExecutableWithCompression()` and `_importExecutableWithCompression()` + methods provided by the `Driver` class have been removed and incorporated + into the new `_getExportExecutable()` and `_getImportExecutable()`; +* `BackupTrait::$validExtensions` has been removed and replaced by the + `DATABASE_BACKUP_EXTENSIONS` constant; +* postgres and sqlite commands are also properly escaped; +* many little fixes and many code simplifications. + ## 2.9 branch ### 2.9.2 * added `BackupTrait::getDriverName()` static method; `getConnection()` and diff --git a/composer.json b/composer.json index 15781463..65ccd879 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ ], "cs-check": "phpcs --standard=phpcs.xml.dist", "cs-fix": "phpcbf --standard=phpcs.xml.dist", - "test": "rm -f -r /tmp/cake* && phpunit", + "test": "rm -f -r /tmp/cake* && phpunit && driver_test=sqlite phpunit && driver_test=postgres phpunit", "coverage": "XDEBUG_MODE=coverage phpunit --coverage-html=coverage", "phpstan": "phpstan.phar analyse", "psalm": "psalm.phar", diff --git a/config/bootstrap.php b/config/bootstrap.php index decfe87f..980474c0 100644 --- a/config/bootstrap.php +++ b/config/bootstrap.php @@ -17,13 +17,32 @@ use Cake\Core\Configure; use Tools\Filesystem; +/** + * Executables. Name of driver as keys, Then, as value, an array that contains + * first the executable to export and then the executable to import backups. + */ +if (!defined('DATABASE_BACKUP_EXECUTABLES')) { + define('DATABASE_BACKUP_EXECUTABLES', [ + 'mysql' => ['export' => 'mysqldump', 'import' => 'mysql'], + 'postgres' => ['export' => 'pg_dump', 'import' => 'pg_restore'], + 'sqlite' => ['export' => 'sqlite3', 'import' => 'sqlite3'], + ]); +} + +/** + * Valid extensions. Names as keys and compressions as values + */ +if (!defined('DATABASE_BACKUP_EXTENSIONS')) { + define('DATABASE_BACKUP_EXTENSIONS', ['sql.bz2' => 'bzip2', 'sql.gz' => 'gzip', 'sql' => false]); +} + //Database connection if (!Configure::check('DatabaseBackup.connection')) { Configure::write('DatabaseBackup.connection', 'default'); } //Auto-discovers binaries -foreach (['mysql', 'mysqldump', 'pg_dump', 'pg_restore','sqlite3', 'bzip2', 'gzip'] as $binary) { +foreach (array_unique(array_merge(array_column(DATABASE_BACKUP_EXECUTABLES, 'export'), array_column(DATABASE_BACKUP_EXECUTABLES, 'import'), ['bzip2', 'gzip'])) as $binary) { if (!Configure::check('DatabaseBackup.binaries.' . $binary)) { try { $binaryPath = which($binary); @@ -38,13 +57,27 @@ Configure::write('DatabaseBackup.chmod', 0664); } +//Default executable commands to export/import databases +foreach ([ + 'DatabaseBackup.mysql.export' => '{{BINARY}} --defaults-file={{AUTH_FILE}} {{DB_NAME}}', + 'DatabaseBackup.mysql.import' => '{{BINARY}} --defaults-extra-file={{AUTH_FILE}} {{DB_NAME}}', + 'DatabaseBackup.postgres.export' => '{{BINARY}} --format=c -b --dbname=\'postgresql://{{DB_USER}}{{DB_PASSWORD}}@{{DB_HOST}}/{{DB_NAME}}\'', + 'DatabaseBackup.postgres.import' => '{{BINARY}} --format=c -c -e --dbname=\'postgresql://{{DB_USER}}{{DB_PASSWORD}}@{{DB_HOST}}/{{DB_NAME}}\'', + 'DatabaseBackup.sqlite.export' => '{{BINARY}} {{DB_NAME}} .dump', + 'DatabaseBackup.sqlite.import' => '{{BINARY}} {{DB_NAME}}', +] as $k => $v) { + if (!Configure::check($k)) { + Configure::write($k, $v); + } +} + //Default target directory if (!Configure::check('DatabaseBackup.target')) { Configure::write('DatabaseBackup.target', Filesystem::instance()->concatenate(ROOT, 'backups')); } //Checks for the target directory -$target = Configure::read('DatabaseBackup.target'); +$target = Configure::readOrFail('DatabaseBackup.target'); if (!file_exists($target)) { mkdir($target, 0777); } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 4b46f7c4..e15adf21 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -21,7 +21,7 @@ parameters: path: tests/TestCase/Driver/DriverTest.php - - message: "#^Negated boolean expression is always false\\.$#" - count: 1 - path: tests/TestCase/Utility/BackupExportTest.php + message: "#^Ternary operator condition is always true\\.$#" + count: 2 + path: tests/TestCase/Utility/BackupImportTest.php diff --git a/psalm.xml b/psalm.xml index 8a6c0b9b..ddd67814 100644 --- a/psalm.xml +++ b/psalm.xml @@ -27,6 +27,12 @@ + + + + + + diff --git a/src/BackupTrait.php b/src/BackupTrait.php index 0c2beb00..4e38bfc2 100644 --- a/src/BackupTrait.php +++ b/src/BackupTrait.php @@ -28,13 +28,6 @@ */ trait BackupTrait { - /** - * Valid extensions. Names as keys and compressions as values - * @since 2.4.0 - * @var array - */ - protected static $validExtensions = ['sql.bz2' => 'bzip2', 'sql.gz' => 'gzip', 'sql' => false]; - /** * Returns the absolute path for a backup file * @param string $path Relative or absolute path @@ -42,25 +35,25 @@ trait BackupTrait */ public static function getAbsolutePath(string $path): string { - return Filesystem::instance()->makePathAbsolute($path, Configure::read('DatabaseBackup.target')); + return Filesystem::instance()->makePathAbsolute($path, Configure::readOrFail('DatabaseBackup.target')); } /** - * Returns the compression type from a filename - * @param string $filename Filename + * Returns the compression type for a backup file + * @param string $path File path * @return string|null Compression type or `null` */ - public static function getCompression(string $filename): ?string + public static function getCompression(string $path): ?string { - $extension = self::getExtension($filename); + $extension = self::getExtension($path); return self::getValidCompressions()[$extension] ?? null; } /** - * Gets the connection array + * Gets the `Connection` instance * @param string|null $name Connection name - * @return \Cake\Datasource\ConnectionInterface A connection object + * @return \Cake\Datasource\ConnectionInterface A `Connection` object */ public static function getConnection(?string $name = null): ConnectionInterface { @@ -68,10 +61,10 @@ public static function getConnection(?string $name = null): ConnectionInterface } /** - * Gets the driver instance containing all methods to export/import database + * Gets the `Driver` instance containing all methods to export/import database * backups, according to the connection - * @param \Cake\Datasource\ConnectionInterface|null $connection A connection object - * @return \DatabaseBackup\Driver\Driver A driver instance + * @param \Cake\Datasource\ConnectionInterface|null $connection A `Connection` object + * @return \DatabaseBackup\Driver\Driver A `Driver` instance * @since 2.0.0 * @throws \InvalidArgumentException */ @@ -87,7 +80,7 @@ public static function getDriver(?ConnectionInterface $connection = null): Drive /** * Gets the driver name, according to the connection - * @param \Cake\Datasource\ConnectionInterface|null $connection A connection object + * @param \Cake\Datasource\ConnectionInterface|null $connection A `Connection` object * @return string Driver name * @since 2.9.2 */ @@ -99,27 +92,24 @@ public static function getDriverName(?ConnectionInterface $connection = null): s } /** - * Returns the extension from a filename - * @param string $filename Filename - * @return string|null Extension or `null` if the extension is not found or - * if is an invalid extension - * @uses $validExtensions + * Returns the extension for a backup file + * @param string $path File path + * @return string|null Extension or `null` for invalid extensions */ - public static function getExtension(string $filename): ?string + public static function getExtension(string $path): ?string { - $extension = Filesystem::instance()->getExtension($filename); + $extension = Filesystem::instance()->getExtension($path); - return in_array($extension, array_keys(self::$validExtensions)) ? $extension : null; + return in_array($extension, array_keys(DATABASE_BACKUP_EXTENSIONS)) ? $extension : null; } /** * Returns all valid compressions - * @return array + * @return array * @since 2.4.0 - * @uses $validExtensions */ public static function getValidCompressions(): array { - return array_filter(self::$validExtensions); + return array_filter(DATABASE_BACKUP_EXTENSIONS); } } diff --git a/src/Command/RotateCommand.php b/src/Command/RotateCommand.php index af6b6856..b42314e3 100644 --- a/src/Command/RotateCommand.php +++ b/src/Command/RotateCommand.php @@ -58,7 +58,7 @@ public function execute(Arguments $args, ConsoleIo $io): void try { //Gets deleted files - $files = (new BackupManager())->rotate((int)$args->getArgument('keep')); + $files = BackupManager::rotate((int)$args->getArgument('keep')); if (!$files) { $io->verbose(__d('database_backup', 'No backup has been deleted')); diff --git a/src/Command/SendCommand.php b/src/Command/SendCommand.php index d0bd8e78..490b722e 100644 --- a/src/Command/SendCommand.php +++ b/src/Command/SendCommand.php @@ -61,7 +61,7 @@ public function execute(Arguments $args, ConsoleIo $io): void parent::execute($args, $io); try { - (new BackupManager())->send($args->getArgument('filename') ?: '', $args->getArgument('recipient') ?: ''); + BackupManager::send($args->getArgument('filename') ?: '', $args->getArgument('recipient') ?: ''); $io->success(__d('database_backup', 'Backup `{0}` was sent via mail', Filesystem::instance()->rtr($args->getArgument('filename') ?: ''))); } catch (Exception $e) { $io->error($e->getMessage()); diff --git a/src/Console/Command.php b/src/Console/Command.php index f44e8394..9f346cec 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -35,10 +35,8 @@ class Command extends BaseCommand */ public function execute(Arguments $args, ConsoleIo $io): void { - $config = $this->getConnection()->config(); - - $io->out(__d('database_backup', 'Connection: {0}', $config['name'])); - $io->out(__d('database_backup', 'Driver: {0}', get_class_short_name($this->getConnection()->getDriver()))); + $io->out(__d('database_backup', 'Connection: {0}', $this->getConnection()->config()['name'])); + $io->out(__d('database_backup', 'Driver: {0}', $this->getDriverName())); $io->hr(); } } diff --git a/src/Driver/Driver.php b/src/Driver/Driver.php index fda66745..0bc47567 100644 --- a/src/Driver/Driver.php +++ b/src/Driver/Driver.php @@ -25,7 +25,7 @@ /** * Represents a driver containing all methods to export/import database backups - * according to the database engine + * according to the connection * @method \Cake\Event\EventManager getEventManager() */ abstract class Driver implements EventListenerInterface @@ -84,16 +84,64 @@ protected function _exec(string $command): Process } /** - * Gets the executable command to export the database + * 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 have the final executables, + * including compression. + * @param string $type Type or the request operation (`export` or `import`) * @return string */ - abstract protected function _exportExecutable(): string; + protected function _getExecutable(string $type): string + { + Exceptionist::inArray([$type, ['export', 'import']]); + $driver = strtolower($this->getDriverName()); + $replacements = [ + '{{BINARY}}' => escapeshellarg($this->getBinary(DATABASE_BACKUP_EXECUTABLES[$driver][$type])), + '{{AUTH_FILE}}' => isset($this->auth) ? escapeshellarg($this->auth) : '', + '{{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); + + return str_replace(array_keys($replacements), $replacements, $exec); + } /** - * Gets the executable command to import the database + * Gets the executable command to export the database, with compression if requested + * @param string $filename Filename where you want to export the database * @return string */ - abstract protected function _importExecutable(): string; + protected function _getExportExecutable(string $filename): string + { + $exec = $this->_getExecutable('export'); + $compression = $this->getCompression($filename); + if ($compression) { + $exec .= ' | ' . escapeshellarg($this->getBinary($compression)); + } + + return $exec . ' > ' . escapeshellarg($filename); + } + + /** + * Gets the executable command to import the database, with compression if requested + * @param string $filename Filename from which you want to import the database + * @return string + */ + protected function _getImportExecutable(string $filename): string + { + $exec = $this->_getExecutable('import'); + $compression = $this->getCompression($filename); + if ($compression) { + return sprintf('%s -dc %s | ', escapeshellarg($this->getBinary($compression)), escapeshellarg($filename)) . $exec; + } + + return $exec . ' < ' . escapeshellarg($filename); + } /** * Called after export @@ -134,32 +182,28 @@ public function beforeImport(): bool } /** - * Gets the executable command to export the database, with compression - * @param string $filename Filename where you want to export the database + * Gets a binary path + * @param string $name Binary name * @return string + * @throws \ErrorException */ - protected function _exportExecutableWithCompression(string $filename): string + final public function getBinary(string $name): string { - $compression = $this->getCompression($filename); - - return $this->_exportExecutable() . ($compression ? ' | ' . escapeshellarg($this->getBinary($compression)) : '') . ' > ' . escapeshellarg($filename); + return Exceptionist::isTrue(Configure::read('DatabaseBackup.binaries.' . $name), sprintf('Binary for `%s` could not be found. You have to set its path manually', $name)); } /** - * Gets the executable command to import the database, with compression - * @param string $filename Filename from which you want to import the database - * @return 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 + * @since 2.3.0 */ - protected function _importExecutableWithCompression(string $filename): string + final public function getConfig(?string $key = null) { - $executable = $this->_importExecutable() . ' < ' . escapeshellarg($filename); - - $compression = $this->getCompression($filename); - if ($compression) { - $executable = sprintf('%s -dc %s | ', escapeshellarg($this->getBinary($compression)), escapeshellarg($filename)) . $this->_importExecutable(); - } + $config = $this->connection->config(); - return $executable; + return $key ? $config[$key] ?? null : $config; } /** @@ -180,7 +224,7 @@ final public function export(string $filename): bool return false; } - $process = $this->_exec($this->_exportExecutableWithCompression($filename)); + $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'); @@ -188,31 +232,6 @@ final public function export(string $filename): bool return file_exists($filename); } - /** - * Gets a binary path - * @param string $name Binary name - * @return string - * @throws \ErrorException - */ - public function getBinary(string $name): string - { - return Exceptionist::isTrue(Configure::read('DatabaseBackup.binaries.' . $name), sprintf('Binary for `%s` could not be found. You have to set its path manually', $name)); - } - - /** - * Gets a config value or the whole configuration - * @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 - * @since 2.3.0 - */ - final public function getConfig(?string $key = null) - { - $config = $this->connection->config(); - - return $key ? $config[$key] ?? null : $config; - } - /** * Imports the database. * @@ -231,7 +250,7 @@ final public function import(string $filename): bool return false; } - $process = $this->_exec($this->_importExecutableWithCompression($filename)); + $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'); diff --git a/src/Driver/Mysql.php b/src/Driver/Mysql.php index 44ed73c7..2220c555 100644 --- a/src/Driver/Mysql.php +++ b/src/Driver/Mysql.php @@ -30,34 +30,6 @@ class Mysql extends Driver */ protected $auth; - /** - * Gets the executable command to export the database - * @return string - */ - protected function _exportExecutable(): string - { - return sprintf( - '%s --defaults-file=%s %s', - escapeshellarg($this->getBinary('mysqldump')), - escapeshellarg($this->auth), - escapeshellarg($this->getConfig('database')) - ); - } - - /** - * Gets the executable command to import the database - * @return string - */ - protected function _importExecutable(): string - { - return sprintf( - '%s --defaults-extra-file=%s %s', - escapeshellarg($this->getBinary('mysql')), - escapeshellarg($this->auth), - escapeshellarg($this->getConfig('database')) - ); - } - /** * Internal method to write an auth file * @param string $content Content diff --git a/src/Driver/Postgres.php b/src/Driver/Postgres.php index 6f1eb0a5..af16fca3 100644 --- a/src/Driver/Postgres.php +++ b/src/Driver/Postgres.php @@ -22,43 +22,4 @@ */ class Postgres extends Driver { - /** - * Gets the value for the `--dbname` option for export and import - * executables as string. It contains the connection string with username, - * password and hostname. - * - * It returns something like: - * - * postgresql://postgres@localhost/travis_ci_test - * - * @return string - */ - protected function getDbnameAsString(): string - { - return sprintf( - 'postgresql://%s%s@%s/%s', - $this->getConfig('username'), - $this->getConfig('password') ? ':' . $this->getConfig('password') : '', - $this->getConfig('host'), - $this->getConfig('database') - ); - } - - /** - * Gets the executable command to export the database - * @return string - */ - protected function _exportExecutable(): string - { - return sprintf('%s --format=c -b --dbname=%s', $this->getBinary('pg_dump'), $this->getDbnameAsString()); - } - - /** - * Gets the executable command to import the database - * @return string - */ - protected function _importExecutable(): string - { - return sprintf('%s --format=c -c -e --dbname=%s', $this->getBinary('pg_restore'), $this->getDbnameAsString()); - } } diff --git a/src/Driver/Sqlite.php b/src/Driver/Sqlite.php index 83c0b27a..f60bfe9f 100644 --- a/src/Driver/Sqlite.php +++ b/src/Driver/Sqlite.php @@ -22,24 +22,6 @@ */ class Sqlite extends Driver { - /** - * Gets the executable command to export the database - * @return string - */ - protected function _exportExecutable(): string - { - return sprintf('%s %s .dump', $this->getBinary('sqlite3'), $this->getConfig('database')); - } - - /** - * Gets the executable command to import the database - * @return string - */ - protected function _importExecutable(): string - { - return sprintf('%s %s', $this->getBinary('sqlite3'), $this->getConfig('database')); - } - /** * Called before import * @return bool diff --git a/src/TestSuite/DriverTestCase.php b/src/TestSuite/DriverTestCase.php index 02f163fb..9064d8c3 100644 --- a/src/TestSuite/DriverTestCase.php +++ b/src/TestSuite/DriverTestCase.php @@ -48,12 +48,6 @@ abstract class DriverTestCase extends TestCase */ protected $DriverClass; - /** - * Auto fixtures - * @var bool - */ - public $autoFixtures = false; - /** * Name of the database connection * @var string @@ -131,8 +125,7 @@ public function testExport(): void */ public function testExportAndImport(): void { - foreach (self::$validExtensions as $extension) { - $this->loadFixtures(); + foreach (DATABASE_BACKUP_EXTENSIONS as $extension) { $backup = uniqid('example_'); $backup = $this->getAbsolutePath($extension ? $backup . '.' . $extension : $backup); @@ -178,34 +171,23 @@ public function testExportAndImport(): void } /** - * Test for `_exportExecutable()` method - * @return void - */ - abstract public function testExportExecutable(): void; - - /** - * Test for `_exportExecutableWithCompression()` method + * Test for `_getExportExecutable()` method * @return void * @test */ - public function testExportExecutableWithCompression(): void + public function testGetExportExecutable(): void { - $basicExecutable = $this->invokeMethod($this->Driver, '_exportExecutable'); - - //No compression - $result = $this->invokeMethod($this->Driver, '_exportExecutableWithCompression', ['backup.sql']); - $this->assertEquals($basicExecutable . ' > ' . escapeshellarg('backup.sql'), $result); + $this->assertNotEmpty($this->invokeMethod($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, '_exportExecutableWithCompression', [$filename]); + $result = $this->invokeMethod($this->Driver, '_getExportExecutable', [$filename]); $expected = sprintf( - '%s | %s > %s', - $basicExecutable, + ' | %s > %s', escapeshellarg($this->Driver->getBinary($compression)), escapeshellarg($filename) ); - $this->assertEquals($expected, $result); + $this->assertStringEndsWith($expected, $result); } } @@ -224,34 +206,23 @@ public function testImport(): void } /** - * Test for `_importExecutable()` method - * @return void - */ - abstract public function testImportExecutable(): void; - - /** - * Test for `_importExecutableWithCompression()` method + * Test for `_getImportExecutable()` method * @return void * @test */ - public function testImportExecutableWithCompression(): void + public function testGetImportExecutable(): void { - $basicExecutable = $this->invokeMethod($this->Driver, '_importExecutable'); - - //No compression - $result = $this->invokeMethod($this->Driver, '_importExecutableWithCompression', ['backup.sql']); - $this->assertEquals($basicExecutable . ' < ' . escapeshellarg('backup.sql'), $result); + $this->assertNotEmpty($this->invokeMethod($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, '_importExecutableWithCompression', [$filename]); + $result = $this->invokeMethod($this->Driver, '_getImportExecutable', [$filename]); $expected = sprintf( - '%s -dc %s | %s', + '%s -dc %s | ', escapeshellarg($this->Driver->getBinary($compression)), - escapeshellarg($filename), - $basicExecutable + escapeshellarg($filename) ); - $this->assertEquals($expected, $result); + $this->assertStringStartsWith($expected, $result); } } } diff --git a/src/Utility/BackupExport.php b/src/Utility/BackupExport.php index 7a615277..6762b9fb 100644 --- a/src/Utility/BackupExport.php +++ b/src/Utility/BackupExport.php @@ -35,7 +35,7 @@ class BackupExport /** * Driver containing all methods to export/import database backups - * according to the database engine + * according to the connection * @since 2.0.0 * @var \DatabaseBackup\Driver\Driver */ diff --git a/src/Utility/BackupImport.php b/src/Utility/BackupImport.php index e982dfd7..d7714cd5 100644 --- a/src/Utility/BackupImport.php +++ b/src/Utility/BackupImport.php @@ -28,11 +28,11 @@ class BackupImport /** * Driver containing all methods to export/import database backups - * according to the database engine + * according to the connection * @since 2.0.0 * @var \DatabaseBackup\Driver\Driver */ - protected $driver; + protected $Driver; /** * Filename where to import the database @@ -45,7 +45,7 @@ class BackupImport */ public function __construct() { - $this->driver = $this->getDriver(); + $this->Driver = $this->getDriver(); } /** @@ -83,7 +83,7 @@ public function import(): string $filename = $this->filename; unset($this->filename); - $this->driver->import($filename); + $this->Driver->import($filename); return $filename; } diff --git a/src/Utility/BackupManager.php b/src/Utility/BackupManager.php index 3b4c767a..bd5d91c1 100644 --- a/src/Utility/BackupManager.php +++ b/src/Utility/BackupManager.php @@ -69,7 +69,7 @@ public static function deleteAll(): array */ public static function index(): CollectionInterface { - $finder = (new Finder())->files()->name('/\.sql(\.(gz|bz2))?$/')->in(Configure::read('DatabaseBackup.target')); + $finder = (new Finder())->files()->name('/\.sql(\.(gz|bz2))?$/')->in(Configure::readOrFail('DatabaseBackup.target')); return collection($finder)->map(function (SplFileInfo $file) { $filename = $file->getFilename(); @@ -128,10 +128,10 @@ protected static function getEmailInstance(string $backup, string $recipient): M * @param string $filename Filename of the backup that you want to send via * email. The path can be relative to the backup directory * @param string $recipient Recipient's email address - * @return array + * @return array{headers: string, message: string} * @since 1.1.0 */ - public function send(string $filename, string $recipient): array + public static function send(string $filename, string $recipient): array { return self::getEmailInstance($filename, $recipient)->send(); } diff --git a/tests/TestCase/BackupTraitTest.php b/tests/TestCase/BackupTraitTest.php index 1a6c12e8..93295f85 100644 --- a/tests/TestCase/BackupTraitTest.php +++ b/tests/TestCase/BackupTraitTest.php @@ -16,7 +16,6 @@ use Cake\Core\Configure; use Cake\Database\Connection; -use Cake\Database\Driver as CakeDriver; use Cake\Database\Driver\Sqlserver; use Cake\Datasource\ConnectionManager; use Cake\Datasource\Exception\MissingDatasourceConfigException; @@ -32,11 +31,6 @@ class BackupTraitTest extends TestCase { use BackupTrait; - /** - * @var bool - */ - public $autoFixtures = false; - /** * Fixtures * @var array @@ -52,9 +46,8 @@ class BackupTraitTest extends TestCase */ public function testGetAbsolutePath(): void { - $this->assertEquals(DS . 'file.txt', $this->getAbsolutePath(DS . 'file.txt')); - $this->assertEquals(Configure::read('DatabaseBackup.target') . DS . 'file.txt', $this->getAbsolutePath('file.txt')); $expected = Configure::read('DatabaseBackup.target') . DS . 'file.txt'; + $this->assertEquals($expected, $this->getAbsolutePath('file.txt')); $this->assertEquals($expected, $this->getAbsolutePath(Configure::read('DatabaseBackup.target') . DS . 'file.txt')); } @@ -67,6 +60,8 @@ public function testGetCompression(): void foreach ([ 'backup.sql' => false, 'backup.sql.bz2' => 'bzip2', + DS . 'backup.sql.bz2' => 'bzip2', + Configure::read('DatabaseBackup.target') . 'backup.sql.bz2' => 'bzip2', 'backup.sql.gz' => 'gzip', 'text.txt' => null, ] as $filename => $expectedCompression) { @@ -80,18 +75,17 @@ public function testGetCompression(): void */ public function testGetConnection(): void { - ConnectionManager::setConfig('fake', ['url' => 'mysql://root:password@localhost/my_database']); - - foreach ([ - null, - Configure::read('DatabaseBackup.connection'), - 'fake', - ] as $name) { + foreach ([null, Configure::read('DatabaseBackup.connection')] as $name) { $connection = $this->getConnection($name); $this->assertInstanceof(Connection::class, $connection); - $this->assertInstanceof(CakeDriver::class, $connection->getDriver()); + $this->assertEquals('test', $connection->config()['name']); } + ConnectionManager::setConfig('fake', ['url' => 'mysql://root:password@localhost/my_database']); + $connection = $this->getConnection('fake'); + $this->assertInstanceof(Connection::class, $connection); + $this->assertEquals('fake', $connection->config()['name']); + $this->expectException(MissingDatasourceConfigException::class); $this->expectExceptionMessage('The datasource configuration "noExisting" was not found'); $this->getConnection('noExisting'); @@ -108,13 +102,13 @@ public function testGetDriver(): void } //With a no existing driver - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('The `Sqlserver` driver does not exist'); - $connection = @$this->getMockBuilder(get_class($this->getConnection())) + $connection = @$this->getMockBuilder(Connection::class) ->setMethods(['getDriver']) - ->setConstructorArgs([$this->getConnection()->config()]) + ->disableOriginalConstructor() ->getMock(); $connection->method('getDriver')->will($this->returnValue(new Sqlserver())); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The `Sqlserver` driver does not exist'); $this->getDriver($connection); } @@ -127,6 +121,8 @@ public function testGetExtension(): void foreach ([ 'backup.sql' => 'sql', 'backup.sql.bz2' => 'sql.bz2', + DS . 'backup.sql.bz2' => 'sql.bz2', + Configure::read('DatabaseBackup.target') . 'backup.sql.bz2' => 'sql.bz2', 'backup.sql.gz' => 'sql.gz', 'backup.SQL' => 'sql', 'backup.SQL.BZ2' => 'sql.bz2', diff --git a/tests/TestCase/Driver/DriverTest.php b/tests/TestCase/Driver/DriverTest.php index cc3ca4e6..f10835f0 100644 --- a/tests/TestCase/Driver/DriverTest.php +++ b/tests/TestCase/Driver/DriverTest.php @@ -29,7 +29,6 @@ class DriverTest extends TestCase { /** - * `Driver` instance * @var \DatabaseBackup\Driver\Driver */ protected $Driver; @@ -48,21 +47,25 @@ protected function getMockForAbstractDriver(array $mockedMethods = []): Driver } /** - * Internal method to get a mock for `Process` class, that returns a failure - * with a custom error message - * @param string $error Custom error message - * @return \Symfony\Component\Process\Process&\PHPUnit\Framework\MockObject\MockObject + * 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 getMockForProcessWithError(string $error): Process + protected function getMockForAbstractDriverWithErrorProcess(string $errorMessage): Driver { $process = @$this->getMockBuilder(Process::class) ->setMethods(['getErrorOutput', 'isSuccessful']) ->setConstructorArgs([[]]) ->getMock(); - $process->method('getErrorOutput')->will($this->returnValue($error . PHP_EOL)); + $process->method('getErrorOutput')->will($this->returnValue($errorMessage . PHP_EOL)); $process->method('isSuccessful')->will($this->returnValue(false)); - return $process; + $Driver = $this->getMockForAbstractDriver(['_exec']); + $Driver->method('_exec')->will($this->returnValue($process)); + + return $Driver; } /** @@ -77,56 +80,55 @@ public function setUp(): void } /** - * Test for `export()` method on failure - * @return void + * Test for `getBinary()` method * @test */ - public function testExportOnFailure(): void + public function testGetBinary(): void { - $expectedError = 'mysqldump: Got error: 1044: "Access denied for user \'root\'@\'localhost\' to database \'noExisting\'" when selecting the database'; + $this->assertStringEndsWith('mysql', $this->Driver->getBinary('mysql')); - $driver = $this->getMockForAbstractDriver(['_exec']); - $driver->method('_exec')->will($this->returnValue($this->getMockForProcessWithError($expectedError . PHP_EOL))); - $this->expectExceptionMessage('Export failed with error message: `' . $expectedError . '`'); - $driver->export($this->getAbsolutePath('example.sql')); + //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'); } /** - * Test for `export()` method. Export is stopped because the - * `beforeExport()` method returns `false` + * Test for `getConfig()` method * @return void * @test */ - public function testExportStoppedByBeforeExport(): void + public function testGetConfig(): void { - $Driver = $this->getMockForAbstractDriver(['beforeExport']); - $Driver->method('beforeExport')->will($this->returnValue(false)); - $this->assertFalse($Driver->export($this->getAbsolutePath('example.sql'))); + $this->assertIsArrayNotEmpty($this->Driver->getConfig()); + $this->assertNotEmpty($this->Driver->getConfig('name')); + $this->assertNull($this->Driver->getConfig('noExistingKey')); } /** - * Test for `getBinary()` method + * Test for `export()` method on failure + * @return void * @test */ - public function testGetBinary(): void + public function testExportOnFailure(): void { - $this->assertEquals(which('mysql'), $this->Driver->getBinary('mysql')); + $expectedError = 'mysqldump: Got error: 1044: "Access denied for user \'root\'@\'localhost\' to database \'noExisting\'" when selecting the database'; - //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'); + $this->expectExceptionMessage('Export failed with error message: `' . $expectedError . '`'); + $Driver = $this->getMockForAbstractDriverWithErrorProcess($expectedError); + $Driver->export($this->getAbsolutePath('example.sql')); } /** - * Test for `getConfig()` method + * Test for `export()` method. Export is stopped because the + * `beforeExport()` method returns `false` * @return void * @test */ - public function testGetConfig(): void + public function testExportStoppedByBeforeExport(): void { - $this->assertIsArrayNotEmpty($this->Driver->getConfig()); - $this->assertNotEmpty($this->Driver->getConfig('name')); - $this->assertNull($this->Driver->getConfig('noExistingKey')); + $Driver = $this->getMockForAbstractDriver(['beforeExport']); + $Driver->method('beforeExport')->will($this->returnValue(false)); + $this->assertFalse($Driver->export($this->getAbsolutePath('example.sql'))); } /** @@ -138,12 +140,9 @@ public function testImportOnFailure(): void { $expectedError = 'ERROR 1044 (42000): Access denied for user \'root\'@\'localhost\' to database \'noExisting\''; - $driver = $this->getMockForAbstractDriver(['_exec']); - $driver->method('_exec')->will($this->returnValue($this->getMockForProcessWithError($expectedError . PHP_EOL))); - - $this->expectException(\ErrorException::class); $this->expectExceptionMessage('Import failed with error message: `' . $expectedError . '`'); - $driver->import($this->getAbsolutePath('example.sql')); + $Driver = $this->getMockForAbstractDriverWithErrorProcess($expectedError); + $Driver->import($this->getAbsolutePath('example.sql')); } /** diff --git a/tests/TestCase/Driver/MysqlTest.php b/tests/TestCase/Driver/MysqlTest.php index d88dd9fd..954d80eb 100644 --- a/tests/TestCase/Driver/MysqlTest.php +++ b/tests/TestCase/Driver/MysqlTest.php @@ -31,52 +31,10 @@ public function setUp(): void parent::setUp(); if (!$this->Driver instanceof Mysql) { - $this->markTestIncomplete(); + $this->markTestSkipped('Skipping tests for Mysql, current driver is ' . $this->Driver->getDriverName()); } } - /** - * Test for `_exportExecutable()` method - * @test - */ - public function testExportExecutable(): void - { - $expected = sprintf('%s --defaults-file=%s %s', escapeshellarg($this->Driver->getBinary('mysqldump')), escapeshellarg('authFile'), escapeshellarg('test')); - $this->setProperty($this->Driver, 'auth', 'authFile'); - $this->assertEquals($expected, $this->invokeMethod($this->Driver, '_exportExecutable')); - } - - /** - * Test for `_exportExecutableWithCompression()` method - * @test - */ - public function testExportExecutableWithCompression(): void - { - $this->setProperty($this->Driver, 'auth', 'authFile'); - parent::testExportExecutableWithCompression(); - } - - /** - * Test for `_importExecutable()` method - * @test - */ - public function testImportExecutable(): void - { - $expected = sprintf('%s --defaults-extra-file=%s %s', escapeshellarg($this->Driver->getBinary('mysql')), escapeshellarg('authFile'), escapeshellarg('test')); - $this->setProperty($this->Driver, 'auth', 'authFile'); - $this->assertEquals($expected, $this->invokeMethod($this->Driver, '_importExecutable')); - } - - /** - * Test for `_importExecutableWithCompression()` method - * @test - */ - public function testImportExecutableWithCompression(): void - { - $this->setProperty($this->Driver, 'auth', 'authFile'); - parent::testImportExecutableWithCompression(); - } - /** * Test for `afterExport()` method * @test @@ -113,8 +71,7 @@ public function testBeforeExport(): void 'password="' . $this->Driver->getConfig('password') . '"' . PHP_EOL . 'host=' . $this->Driver->getConfig('host'); $auth = $this->getProperty($this->Driver, 'auth'); - $this->assertFileExists($auth); - $this->assertEquals($expected, file_get_contents($auth)); + $this->assertStringEqualsFile($auth, $expected); @unlink($auth); } @@ -133,8 +90,9 @@ public function testBeforeImport(): void 'password="' . $this->Driver->getConfig('password') . '"' . PHP_EOL . 'host=' . $this->Driver->getConfig('host'); $auth = $this->getProperty($this->Driver, 'auth'); - $this->assertFileExists($auth); - $this->assertEquals($expected, file_get_contents($auth)); + $this->assertStringEqualsFile($auth, $expected); + + @unlink($auth); } /** diff --git a/tests/TestCase/Driver/PostgresTest.php b/tests/TestCase/Driver/PostgresTest.php index b6da8465..b9c1929d 100644 --- a/tests/TestCase/Driver/PostgresTest.php +++ b/tests/TestCase/Driver/PostgresTest.php @@ -14,7 +14,6 @@ */ namespace DatabaseBackup\Test\TestCase\Driver; -use Cake\Database\Connection; use DatabaseBackup\Driver\Postgres; use DatabaseBackup\TestSuite\DriverTestCase; @@ -32,54 +31,7 @@ public function setUp(): void parent::setUp(); if (!$this->Driver instanceof Postgres) { - $this->markTestIncomplete(); + $this->markTestSkipped('Skipping tests for Postgres, current driver is ' . $this->Driver->getDriverName()); } } - - /** - * Test for `getDbnameAsString()` method - * @test - */ - public function testGetDbnameAsString(): void - { - $password = $this->Driver->getConfig('password'); - $expected = 'postgresql://postgres' . ($password ? ':' . $password : null) . '@' . $this->Driver->getConfig('host') . '/' . $this->Driver->getConfig('database'); - $this->assertEquals($expected, $this->invokeMethod($this->Driver, 'getDbnameAsString')); - - //Adds a password to the config - $expected = 'postgresql://postgres:mypassword@' . $this->Driver->getConfig('host') . '/' . $this->Driver->getConfig('database'); - $config = ['password' => 'mypassword'] + $this->Driver->getConfig(); - $this->setProperty($this->Driver, 'connection', new Connection($config)); - $this->assertEquals($expected, $this->invokeMethod($this->Driver, 'getDbnameAsString')); - } - - /** - * Test for `_exportExecutable()` method - * @test - */ - public function testExportExecutable(): void - { - $password = $this->Driver->getConfig('password'); - $expected = sprintf( - '%s --format=c -b --dbname=postgresql://postgres%s@' . $this->Driver->getConfig('host') . '/' . $this->Driver->getConfig('database'), - $this->Driver->getBinary('pg_dump'), - $password ? ':' . $password : '' - ); - $this->assertEquals($expected, $this->invokeMethod($this->Driver, '_exportExecutable')); - } - - /** - * Test for `_importExecutable()` method - * @test - */ - public function testImportExecutable(): void - { - $password = $this->Driver->getConfig('password'); - $expected = sprintf( - '%s --format=c -c -e --dbname=postgresql://postgres%s@' . $this->Driver->getConfig('host') . '/' . $this->Driver->getConfig('database'), - $this->Driver->getBinary('pg_restore'), - $password ? ':' . $password : '' - ); - $this->assertEquals($expected, $this->invokeMethod($this->Driver, '_importExecutable')); - } } diff --git a/tests/TestCase/Driver/SqliteTest.php b/tests/TestCase/Driver/SqliteTest.php index 28d9116d..34a4a2b7 100644 --- a/tests/TestCase/Driver/SqliteTest.php +++ b/tests/TestCase/Driver/SqliteTest.php @@ -31,37 +31,7 @@ public function setUp(): void parent::setUp(); if (!$this->Driver instanceof Sqlite) { - $this->markTestIncomplete(); + $this->markTestSkipped('Skipping tests for Sqlite, current driver is ' . $this->Driver->getDriverName()); } } - - /** - * Test for `_exportExecutable()` method - * @test - */ - public function testExportExecutable(): void - { - $expected = $this->Driver->getBinary('sqlite3') . ' ' . TMP . 'test.sq3 .dump'; - $this->assertEquals($expected, $this->invokeMethod($this->Driver, '_exportExecutable')); - } - - /** - * Test for `_importExecutable()` method - * @test - */ - public function testImportExecutable(): void - { - $expected = $this->Driver->getBinary('sqlite3') . ' ' . TMP . 'test.sq3'; - $this->assertEquals($expected, $this->invokeMethod($this->Driver, '_importExecutable')); - } - - /** - * Test for `import()` method - * @test - */ - public function testImport(): void - { - $this->loadFixtures(); - parent::testImport(); - } } diff --git a/tests/TestCase/I18nTest.php b/tests/TestCase/I18nTest.php index 55694f4a..3a82ba21 100644 --- a/tests/TestCase/I18nTest.php +++ b/tests/TestCase/I18nTest.php @@ -30,6 +30,6 @@ class I18nTest extends TestCase public function testI18nConstant(): void { $translator = I18n::getTranslator('database_backup', 'it'); - $this->assertEquals('Esporta un backup del database', $translator->translate('Exports a database backup')); + $this->assertNotEquals('Exports a database backup', $translator->translate('Exports a database backup')); } } diff --git a/tests/TestCase/Utility/BackupExportTest.php b/tests/TestCase/Utility/BackupExportTest.php index 55403a36..7cf111ec 100644 --- a/tests/TestCase/Utility/BackupExportTest.php +++ b/tests/TestCase/Utility/BackupExportTest.php @@ -15,11 +15,8 @@ namespace DatabaseBackup\Test\TestCase\Utility; use Cake\Core\Configure; -use Cake\Log\Log; -use DatabaseBackup\Driver\Driver; +use Cake\TestSuite\EmailTrait; use DatabaseBackup\TestSuite\TestCase; -use DatabaseBackup\Utility\BackupExport; -use DatabaseBackup\Utility\BackupManager; use InvalidArgumentException; use Tools\Filesystem; @@ -28,56 +25,7 @@ */ class BackupExportTest extends TestCase { - /** - * @var \DatabaseBackup\Utility\BackupExport - */ - protected $BackupExport; - - /** - * Called before every test method - * @return void - */ - public function setUp(): void - { - if (!$this->BackupExport) { - $this->BackupExport = new BackupExport(); - - //Mocks the `send()` method of `BackupManager` class, so that it writes - // on the debug log instead of sending a real mail - $this->BackupExport->BackupManager = @$this->getMockBuilder(BackupManager::class) - ->setMethods(['send']) - ->getMock(); - - $this->BackupExport->BackupManager->method('send') - ->will($this->returnCallback(function () { - $args = implode(', ', array_map(function ($arg) { - return '`' . $arg . '`'; - }, func_get_args())); - - Log::write('debug', 'Called `send()` with args: ' . $args); - - return func_get_args(); - })); - } - - parent::setUp(); - } - - /** - * Test for `construct()` method - * @test - */ - public function testConstruct(): void - { - $this->assertNull($this->getProperty($this->BackupExport, 'compression')); - - $this->assertInstanceof(Driver::class, $this->BackupExport->Driver); - $this->assertEquals('sql', $this->getProperty($this->BackupExport, 'defaultExtension')); - $this->assertNull($this->getProperty($this->BackupExport, 'emailRecipient')); - $this->assertNull($this->getProperty($this->BackupExport, 'extension')); - $this->assertNull($this->getProperty($this->BackupExport, 'filename')); - $this->assertEquals(0, $this->getProperty($this->BackupExport, 'rotate')); - } + use EmailTrait; /** * Test for `compression()` method. This also tests for `$extension` @@ -174,25 +122,27 @@ public function testSend(): void */ public function testExport(): void { - $filename = $this->BackupExport->export(); - $this->assertFileExists($filename); - $this->assertMatchesRegularExpression('/^backup_test_\d{14}\.sql$/', basename($filename)); + $file = $this->BackupExport->export(); + $this->assertFileExists($file); + $this->assertMatchesRegularExpression('/^backup_test_\d{14}\.sql$/', basename($file)); //Exports with `compression()` - $filename = $this->BackupExport->compression('bzip2')->export(); - $this->assertFileExists($filename); - $this->assertMatchesRegularExpression('/^backup_test_\d{14}\.sql\.bz2$/', basename($filename)); + $file = $this->BackupExport->compression('bzip2')->export(); + $this->assertFileExists($file); + $this->assertMatchesRegularExpression('/^backup_test_\d{14}\.sql\.bz2$/', basename($file)); //Exports with `filename()` - $filename = $this->BackupExport->filename('backup.sql.bz2')->export(); - $this->assertFileExists($filename); - $this->assertEquals('backup.sql.bz2', basename($filename)); + $file = $this->BackupExport->filename('backup.sql.bz2')->export(); + $this->assertFileExists($file); + $this->assertEquals('backup.sql.bz2', basename($file)); //Exports with `send()` $recipient = 'recipient@example.com'; - $filename = $this->BackupExport->filename('exportWithSend.sql')->send($recipient)->export(); - $log = file_get_contents(LOGS . 'debug.log') ?: ''; - $this->assertTextContains('Called `send()` with args: `' . $filename . '`, `' . $recipient . '`', $log); + $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'); + $this->assertMailContainsAttachment(basename($file), compact('file') + ['mimetype' => mime_content_type($file)]); //With a file that already exists $this->expectExceptionMessage('File `' . $this->BackupExport->getAbsolutePath('backup.sql.bz2') . '` already exists'); @@ -206,11 +156,11 @@ public function testExport(): void */ public function testExportWithDifferendChmod(): void { - $filename = $this->BackupExport->filename('exportWithNormalChmod.sql')->export(); - $this->assertEquals('0664', substr(sprintf('%o', fileperms($filename)), -4)); + $file = $this->BackupExport->filename('exportWithNormalChmod.sql')->export(); + $this->assertEquals('0664', substr(sprintf('%o', fileperms($file)), -4)); Configure::write('DatabaseBackup.chmod', 0777); - $filename = $this->BackupExport->filename('exportWithDifferentChmod.sql')->export(); - $this->assertEquals('0777', substr(sprintf('%o', fileperms($filename)), -4)); + $file = $this->BackupExport->filename('exportWithDifferentChmod.sql')->export(); + $this->assertEquals('0777', substr(sprintf('%o', fileperms($file)), -4)); } } diff --git a/tests/TestCase/Utility/BackupImportTest.php b/tests/TestCase/Utility/BackupImportTest.php index e6c54e18..62abab46 100644 --- a/tests/TestCase/Utility/BackupImportTest.php +++ b/tests/TestCase/Utility/BackupImportTest.php @@ -14,7 +14,6 @@ */ namespace DatabaseBackup\Test\TestCase\Utility; -use DatabaseBackup\Driver\Driver; use DatabaseBackup\TestSuite\TestCase; use DatabaseBackup\Utility\BackupExport; use DatabaseBackup\Utility\BackupImport; @@ -45,18 +44,8 @@ public function setUp(): void { parent::setUp(); - $this->BackupExport = $this->BackupExport ?? new BackupExport(); - $this->BackupImport = $this->BackupImport ?? new BackupImport(); - } - - /** - * Test for `construct()` method - * @test - */ - public function testConstruct(): void - { - $this->assertInstanceof(Driver::class, $this->getProperty($this->BackupImport, 'driver')); - $this->assertNull($this->getProperty($this->BackupImport, 'filename')); + $this->BackupExport = $this->BackupExport ?: new BackupExport(); + $this->BackupImport = $this->BackupImport ?: new BackupImport(); } /** diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 44403c73..f8e1e203 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -16,7 +16,6 @@ use Cake\Cache\Cache; use Cake\Core\Configure; use Cake\Datasource\ConnectionManager; -use Cake\Log\Log; use Cake\Mailer\Email; use Cake\Mailer\TransportFactory; use Cake\TestSuite\TestEmailTransport; @@ -70,7 +69,10 @@ 'cssBaseUrl' => 'css/', 'paths' => ['plugins' => [APP . 'Plugin' . DS]], ]); -Configure::write('Error.ignoredDeprecationPaths', '*/cakephp/cakephp/src/TestSuite/Fixture/FixtureInjector.php'); +/** + * @todo Upgrade fixtures: https://book.cakephp.org/4/en/appendices/fixture-upgrade.html + */ +Configure::write('Error.ignoredDeprecationPaths', ['*/cakephp/src/TestSuite/Fixture/FixtureInjector.php']); Cache::setConfig([ '_cake_core_' => [ @@ -80,12 +82,6 @@ ], ]); -Log::setConfig('debug', [ - 'className' => 'File', - 'path' => LOGS, - 'levels' => ['notice', 'info', 'debug'], - 'file' => 'debug', -]); TransportFactory::setConfig('debug', ['className' => TestEmailTransport::class]); Email::setConfig('default', ['transport' => 'debug']); diff --git a/version b/version index 5d9ade10..74c97772 100644 --- a/version +++ b/version @@ -1 +1 @@ -2.9.2 +2.10.0-beta1