diff --git a/app/modules/cli/Commands/BackupCommand.php b/app/modules/cli/Commands/BackupCommand.php new file mode 100644 index 00000000..7aec502e --- /dev/null +++ b/app/modules/cli/Commands/BackupCommand.php @@ -0,0 +1,140 @@ +. + */ + +namespace SP\Modules\Cli\Commands; + +use Exception; +use Psr\Log\LoggerInterface; +use RuntimeException; +use SP\Config\Config; +use SP\Services\Backup\FileBackupService; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\StyleInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +/** + * Class BackupCommand + * + * @package SP\Modules\Cli\Commands + */ +final class BackupCommand extends CommandBase +{ + /** + * @var string[] + */ + public static array $envVarsMapping = [ + 'path' => 'BACKUP_PATH' + ]; + /** + * @var string + */ + protected static $defaultName = 'sp:backup'; + /** + * @var FileBackupService + */ + private FileBackupService $fileBackupService; + + public function __construct(FileBackupService $fileBackupService, + LoggerInterface $logger, + Config $config) + { + $this->fileBackupService = $fileBackupService; + + parent::__construct($logger, $config); + } + + protected function configure(): void + { + $this->setDescription(__('Backup actions')) + ->setHelp(__('This command performs a file based backup from sysPass database and application')) + ->addOption('path', + null, + InputOption::VALUE_OPTIONAL, + __('Path where to store the backup files'), + BACKUP_PATH); + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output): int + { + $style = new SymfonyStyle($input, $output); + + try { + $this->checkInstalled(); + + $path = $this->getPath($input, $style); + + $this->logger->info(sprintf(__u('Backup path set to: %s'), $path)); + + $this->fileBackupService->doBackup($path); + + $this->logger->info(__u('Application and database backup completed successfully')); + + $style->success(__('Application and database backup completed successfully')); + + return self::SUCCESS; + } catch (Exception $e) { + $this->logger->error($e->getTraceAsString()); + $this->logger->error($e->getMessage()); + + $style->error(__($e->getMessage())); + } + + return self::FAILURE; + } + + private function checkInstalled(): void + { + if (!defined('TEST_ROOT') + && !$this->configData->isInstalled()) { + throw new RuntimeException(__u('sysPass is not installed')); + } + } + + /** + * @param InputInterface $input + * @param StyleInterface $style + * + * @return string + */ + private function getPath(InputInterface $input, StyleInterface $style): string + { + $path = self::getEnvVarOrOption('path', $input); + + if (empty($path)) { + $this->logger->debug(__u('Ask for path')); + + return $style->ask(__('Please enter the path where to store the backup files'), BACKUP_PATH); + } + + return $path; + } +} \ No newline at end of file diff --git a/app/modules/cli/Commands/CommandBase.php b/app/modules/cli/Commands/CommandBase.php index d841b433..32e147fa 100644 --- a/app/modules/cli/Commands/CommandBase.php +++ b/app/modules/cli/Commands/CommandBase.php @@ -28,6 +28,7 @@ use Psr\Log\LoggerInterface; use SP\Config\Config; use SP\Config\ConfigData; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; /** * Class CommandBase @@ -36,19 +37,22 @@ use Symfony\Component\Console\Command\Command; */ abstract class CommandBase extends Command { + /** + * @var string[] + */ + public static array $envVarsMapping = []; /** * @var LoggerInterface */ - protected $logger; - + protected LoggerInterface $logger; /** * @var Config */ - protected $config; + protected Config $config; /** * @var ConfigData */ - protected $configData; + protected ConfigData $configData; /** * CommandBase constructor. @@ -67,4 +71,44 @@ abstract class CommandBase extends Command parent::__construct(); } + + /** + * @param string $option + * @param InputInterface $input + * + * @return array|false|mixed|string + */ + protected static function getEnvVarOrOption( + string $option, + InputInterface $input + ) + { + return static::getEnvVarForOption($option) + ?: $input->getOption($option); + } + + /** + * @param string $option + * + * @return string|false + */ + protected static function getEnvVarForOption(string $option) + { + return getenv(static::$envVarsMapping[$option]); + } + + /** + * @param string $argument + * @param InputInterface $input + * + * @return array|false|mixed|string + */ + protected static function getEnvVarOrArgument( + string $argument, + InputInterface $input + ) + { + return static::getEnvVarForOption($argument) + ?: $input->getArgument($argument); + } } \ No newline at end of file diff --git a/app/modules/cli/Commands/InstallCommand.php b/app/modules/cli/Commands/InstallCommand.php index 65d024af..05bf48a5 100644 --- a/app/modules/cli/Commands/InstallCommand.php +++ b/app/modules/cli/Commands/InstallCommand.php @@ -27,7 +27,6 @@ namespace SP\Modules\Cli\Commands; use Closure; use Exception; use Psr\Log\LoggerInterface; -use RuntimeException; use SP\Config\Config; use SP\Core\Exceptions\InstallError; use SP\Core\Exceptions\InvalidArgumentException; @@ -52,7 +51,7 @@ final class InstallCommand extends CommandBase /** * @var string[] */ - public static $envVarsMapping = [ + public static array $envVarsMapping = [ 'adminLogin' => 'ADMIN_LOGIN', 'adminPassword' => 'ADMIN_PASSWORD', 'databaseHost' => 'DATABASE_HOST', @@ -72,7 +71,7 @@ final class InstallCommand extends CommandBase /** * @var Installer */ - private $installer; + private Installer $installer; public function __construct(LoggerInterface $logger, Config $config, @@ -185,16 +184,8 @@ final class InstallCommand extends CommandBase */ private function getInstallData(InputInterface $input, StyleInterface $style): InstallData { - $passNotEmptyValidator = function ($value) { - if (empty($value)) { - throw new RuntimeException(__('Password cannot be blank')); - } - - return $value; - }; - - $adminPassword = $this->getAdminPassword($input, $style, $passNotEmptyValidator); - $masterPassword = $this->getMasterPassword($input, $style, $passNotEmptyValidator); + $adminPassword = $this->getAdminPassword($input, $style); + $masterPassword = $this->getMasterPassword($input, $style); $databasePassword = $this->getDatabasePassword($input, $style); $language = $this->getLanguage($input, $style); $hostingMode = $this->isHostingMode($input); @@ -220,15 +211,13 @@ final class InstallCommand extends CommandBase /** * @param InputInterface $input * @param StyleInterface $style - * @param Closure $passNotEmptyValidator * * @return array|false|mixed|string * @throws InstallError */ private function getAdminPassword( InputInterface $input, - StyleInterface $style, - Closure $passNotEmptyValidator + StyleInterface $style ) { $option = 'adminPassword'; @@ -242,12 +231,18 @@ final class InstallCommand extends CommandBase $password = $style->askHidden( __('Please provide sysPass admin\'s password'), - $passNotEmptyValidator + fn($value) => Validators::valueNotEmpty( + $value, + sprintf(__u('%s cannot be blank'), 'Admin password') + ) ); $passwordRepeat = $style->askHidden( __('Please provide sysPass admin\'s password again'), - $passNotEmptyValidator + fn($value) => Validators::valueNotEmpty( + $value, + sprintf(__u('%s cannot be blank'), 'Admin password') + ) ); if ($password !== $passwordRepeat) { @@ -260,18 +255,17 @@ final class InstallCommand extends CommandBase return $password; } + /** * @param InputInterface $input * @param StyleInterface $style - * @param Closure $passNotEmptyValidator * * @return array|false|mixed|string * @throws InstallError */ private function getMasterPassword( InputInterface $input, - StyleInterface $style, - Closure $passNotEmptyValidator + StyleInterface $style ) { $password = self::getEnvVarOrOption('masterPassword', $input); @@ -281,11 +275,17 @@ final class InstallCommand extends CommandBase $password = $style->askHidden( __('Please provide sysPass master password'), - $passNotEmptyValidator + fn($value) => Validators::valueNotEmpty( + $value, + sprintf(__u('%s cannot be blank'), 'Master password') + ) ); $passwordRepeat = $style->askHidden( __('Please provide sysPass master password again'), - $passNotEmptyValidator + fn($value) => Validators::valueNotEmpty( + $value, + sprintf(__u('%s cannot be blank'), 'Master password') + ) ); if ($password !== $passwordRepeat) { @@ -298,31 +298,6 @@ final class InstallCommand extends CommandBase return $password; } - /** - * @param string $option - * @param InputInterface $input - * - * @return array|false|mixed|string - */ - private static function getEnvVarOrOption( - string $option, - InputInterface $input - ) - { - return self::getEnvVarForOption($option) - ?: $input->getOption($option); - } - - /** - * @param string $option - * - * @return string|false - */ - public static function getEnvVarForOption(string $option) - { - return getenv(self::$envVarsMapping[$option]); - } - /** * @param InputInterface $input * @param StyleInterface $style @@ -387,21 +362,6 @@ final class InstallCommand extends CommandBase : $input->getOption($option); } - /** - * @param string $argument - * @param InputInterface $input - * - * @return array|false|mixed|string - */ - private static function getEnvVarOrArgument( - string $argument, - InputInterface $input - ) - { - return self::getEnvVarForOption($argument) - ?: $input->getArgument($argument); - } - /** * @param InputInterface $input * diff --git a/app/modules/cli/Commands/Validators.php b/app/modules/cli/Commands/Validators.php new file mode 100644 index 00000000..6cf02631 --- /dev/null +++ b/app/modules/cli/Commands/Validators.php @@ -0,0 +1,48 @@ +. + */ + +namespace SP\Modules\Cli\Commands; + +use RuntimeException; + +/** + * + */ +final class Validators +{ + /** + * @param string|null $value + * @param string|null $message + * + * @return string + */ + public static function valueNotEmpty(?string $value, ?string $message): string + { + if (empty($value)) { + throw new RuntimeException($message ?? __u('Value cannot be blank')); + } + + return $value; + } +} \ No newline at end of file diff --git a/app/modules/cli/Init.php b/app/modules/cli/Init.php index 722f8e87..32db8c6d 100644 --- a/app/modules/cli/Init.php +++ b/app/modules/cli/Init.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2020, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2021, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -19,7 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with sysPass. If not, see . + * along with sysPass. If not, see . */ namespace SP\Modules\Cli; @@ -32,6 +32,7 @@ use SP\Core\Context\ContextException; use SP\Core\Context\StatelessContext; use SP\Core\Language; use SP\Core\ModuleBase; +use SP\Modules\Cli\Commands\BackupCommand; use SP\Modules\Cli\Commands\InstallCommand; use SP\Util\VersionUtil; use Symfony\Component\Console\Application; @@ -46,7 +47,8 @@ use Symfony\Component\Console\Output\OutputInterface; final class Init extends ModuleBase { private const CLI_COMMANDS = [ - InstallCommand::class + InstallCommand::class, + BackupCommand::class ]; /** * @var StatelessContext diff --git a/app/modules/cli/module.php b/app/modules/cli/module.php index 205d247e..62202b4f 100644 --- a/app/modules/cli/module.php +++ b/app/modules/cli/module.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2020, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2021, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -19,8 +19,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with sysPass. If not, see . + * along with sysPass. If not, see . */ -define('MODULE_PATH', __DIR__); -define('PLUGINS_PATH', MODULE_PATH . DIRECTORY_SEPARATOR . 'plugins'); +const MODULE_PATH = __DIR__; +const PLUGINS_PATH = MODULE_PATH . DIRECTORY_SEPARATOR . 'plugins'; diff --git a/lib/SP/Config/Config.php b/lib/SP/Config/Config.php index f30eb82f..ff02d557 100644 --- a/lib/SP/Config/Config.php +++ b/lib/SP/Config/Config.php @@ -202,15 +202,18 @@ final class Config * @return Config * @throws FileException */ - public function saveConfig(ConfigData $configData, $backup = true): Config + public function saveConfig(ConfigData $configData, ?bool $backup = true): Config { if ($backup) { $this->dic->get(ConfigBackupService::class) ->backup($configData); } + $configSaver = $this->context->getUserData()->getLogin() + ?: AppInfoInterface::APP_NAME; + $configData->setConfigDate(time()); - $configData->setConfigSaver($this->context->getUserData()->getLogin() ?: AppInfoInterface::APP_NAME); + $configData->setConfigSaver($configSaver); $configData->setConfigHash(); // Save only attributes to avoid a parent attributes node within the XML @@ -258,7 +261,7 @@ final class Config * * @return ConfigData */ - public function loadConfig($reload = false): ConfigData + public function loadConfig(?bool $reload = false): ConfigData { try { $configData = $this->fileCache->load(); diff --git a/lib/SP/Core/Context/ContextInterface.php b/lib/SP/Core/Context/ContextInterface.php index 46390c2b..fda059e6 100644 --- a/lib/SP/Core/Context/ContextInterface.php +++ b/lib/SP/Core/Context/ContextInterface.php @@ -85,9 +85,9 @@ interface ContextInterface /** * Devuelve los datos del usuario en la sesión. * - * @return UserLoginResponse|null + * @return UserLoginResponse */ - public function getUserData(): ?UserLoginResponse; + public function getUserData(): UserLoginResponse; /** * Establecer el lenguaje de la sesión diff --git a/lib/SP/Core/Context/StatelessContext.php b/lib/SP/Core/Context/StatelessContext.php index 521f3850..963e7c00 100644 --- a/lib/SP/Core/Context/StatelessContext.php +++ b/lib/SP/Core/Context/StatelessContext.php @@ -119,7 +119,7 @@ final class StatelessContext extends ContextBase * * @return UserLoginResponse */ - public function getUserData(): ?UserLoginResponse + public function getUserData(): UserLoginResponse { return $this->getContextKey('userData', new UserLoginResponse()); } diff --git a/lib/SP/Providers/Auth/Ldap/LdapConnection.php b/lib/SP/Providers/Auth/Ldap/LdapConnection.php index b0d83959..aed48f7a 100644 --- a/lib/SP/Providers/Auth/Ldap/LdapConnection.php +++ b/lib/SP/Providers/Auth/Ldap/LdapConnection.php @@ -203,22 +203,6 @@ final class LdapConnection implements LdapConnectionInterface return $this; } - public function getServerUri(): string - { - $server = $this->getServer(); - $port = $this->ldapParams->getPort(); - - if (strpos($server, '://') !== false) { - return $server . ':' . $port; - } elseif ($port === 389 || $port === null) { - return 'ldap://' . $server; - } elseif ($port === 636) { - return 'ldaps://' . $server; - } - - return 'ldap://' . $server . ':' . $port; - } - /** * @inheritDoc */ @@ -229,9 +213,13 @@ final class LdapConnection implements LdapConnectionInterface if (strpos($server, '://') !== false) { return $server . ':' . $port; - } elseif ($port === 389 || $port === null) { + } + + if ($port === 389 || $port === null) { return 'ldap://' . $server; - } elseif ($port === 636) { + } + + if ($port === 636) { return 'ldaps://' . $server; } diff --git a/lib/SP/Services/Backup/FileBackupService.php b/lib/SP/Services/Backup/FileBackupService.php index d29ca87a..4e552dcb 100644 --- a/lib/SP/Services/Backup/FileBackupService.php +++ b/lib/SP/Services/Backup/FileBackupService.php @@ -137,13 +137,14 @@ final class FileBackupService extends Service /** * Comprobar y crear el directorio de backups. * - * @return bool + * @return void * @throws ServiceException */ - private function checkBackupDir() + private function checkBackupDir(): void { if (is_dir($this->path) === false - && @mkdir($this->path, 0750) === false + && !@mkdir($concurrentDirectory = $this->path, 0750) + && !is_dir($concurrentDirectory) ) { throw new ServiceException( sprintf(__('Unable to create the backups directory ("%s")'), $this->path)); @@ -154,7 +155,6 @@ final class FileBackupService extends Service __u('Please, check the backup directory permissions')); } - return true; } /** diff --git a/lib/SP/Util/FileUtil.php b/lib/SP/Util/FileUtil.php index d2162957..8c41044d 100644 --- a/lib/SP/Util/FileUtil.php +++ b/lib/SP/Util/FileUtil.php @@ -54,11 +54,19 @@ final class FileUtil throw new FileNotFoundException('Directory does not exist'); } - $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST); + $it = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator( + $dir, + FilesystemIterator::SKIP_DOTS), + RecursiveIteratorIterator::CHILD_FIRST + ); foreach ($it as $file) { - if ($file->isDir()) rmdir($file->getPathname()); - else unlink($file->getPathname()); + if ($file->isDir()) { + rmdir($file->getPathname()); + } else { + unlink($file->getPathname()); + } } return rmdir($dir); diff --git a/tests/SP/Modules/Cli/CliTestCase.php b/tests/SP/Modules/Cli/CliTestCase.php index 85a91919..35d10d9e 100644 --- a/tests/SP/Modules/Cli/CliTestCase.php +++ b/tests/SP/Modules/Cli/CliTestCase.php @@ -25,9 +25,15 @@ namespace SP\Tests\Modules\Cli; use DI\ContainerBuilder; +use DI\DependencyException; +use DI\NotFoundException; use Exception; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; +use SP\Core\Context\ContextInterface; +use SP\Storage\Database\DBStorageInterface; +use Symfony\Component\Console\Tester\CommandTester; +use function SP\Tests\getDbHandler; /** * Class CliTestCase @@ -40,6 +46,10 @@ abstract class CliTestCase extends TestCase * @var ContainerInterface */ protected static $dic; + /** + * @var string[] + */ + protected static array $commandInputData = []; /** * This method is called before the first test of this test class is run. @@ -57,5 +67,43 @@ abstract class CliTestCase extends TestCase ); self::$dic = $builder->build(); + + $context = self::$dic->get(ContextInterface::class); + $context->initialize(); + } + + /** + * @param string $commandClass + * @param array|null $inputData + * @param bool $useInputData + * + * @return CommandTester + * @throws DependencyException + * @throws NotFoundException + */ + protected function executeCommandTest( + string $commandClass, + ?array $inputData = null, + bool $useInputData = true + ): CommandTester + { + $installCommand = self::$dic->get($commandClass); + + if (null === $inputData && $useInputData) { + $inputData = static::$commandInputData; + } + + $commandTester = new CommandTester($installCommand); + $commandTester->execute( + $inputData ?? [], + ['interactive' => false] + ); + + return $commandTester; + } + + protected function setupDatabase(): void + { + self::$dic->set(DBStorageInterface::class, getDbHandler()); } } \ No newline at end of file diff --git a/tests/SP/Modules/Cli/Commands/BackupCommandTest.php b/tests/SP/Modules/Cli/Commands/BackupCommandTest.php new file mode 100644 index 00000000..37d19a9a --- /dev/null +++ b/tests/SP/Modules/Cli/Commands/BackupCommandTest.php @@ -0,0 +1,168 @@ +. + */ + +namespace SP\Tests\Modules\Cli\Commands; + +use DI\DependencyException; +use DI\NotFoundException; +use SP\Config\Config; +use SP\Core\Exceptions\FileNotFoundException; +use SP\Modules\Cli\Commands\BackupCommand; +use SP\Services\Backup\FileBackupService; +use SP\Tests\Modules\Cli\CliTestCase; +use function SP\Tests\recreateDir; + +/** + * + */ +class BackupCommandTest extends CliTestCase +{ + /** + * @var string + */ + protected static string $currentConfig; + /** + * @var string[] + */ + protected static array $commandInputData = [ + '--path' => TMP_PATH + ]; + + /** + * @throws DependencyException + * @throws NotFoundException + */ + public function testBackupFails(): void + { + $inputData = ['--path' => '/non/existant/path']; + + $commandTester = $this->executeCommandTest( + BackupCommand::class, + $inputData + ); + + // the output of the command in the console + $output = $commandTester->getDisplay(); + $this->assertStringContainsString('Unable to create the backups directory', $output); + } + + /** + * @throws DependencyException + * @throws FileNotFoundException + * @throws NotFoundException + */ + public function testBackupIsSuccessful(): void + { + $this->setupDatabase(); + + $commandTester = $this->executeCommandTest( + BackupCommand::class, + self::$commandInputData + ); + + // the output of the command in the console + $output = $commandTester->getDisplay(); + $this->assertStringContainsString('Application and database backup completed successfully', $output); + + $this->checkBackupFilesAreCreated(); + + // Recreate cache directory to avoid unwanted behavior + recreateDir(CACHE_PATH); + } + + private function checkBackupFilesAreCreated(): void + { + $configData = self::$dic->get(Config::class)->getConfigData(); + + $this->assertFileExists( + FileBackupService::getAppBackupFilename( + TMP_PATH, + $configData->getBackupHash(), + true + ) + ); + $this->assertFileExists( + FileBackupService::getDbBackupFilename( + TMP_PATH, + $configData->getBackupHash(), + true + ) + ); + } + + /** + * @throws DependencyException + * @throws NotFoundException + */ + public function testBackupFromEnvironmentVarIsAbort(): void + { + putenv(sprintf('%s=%s', + BackupCommand::$envVarsMapping['path'], + '/non/existant/path') + ); + + $commandTester = $this->executeCommandTest( + BackupCommand::class, + null, + false + ); + + // the output of the command in the console + $output = $commandTester->getDisplay(); + $this->assertStringContainsString('Unable to create the backups directory', $output); + } + + /** + * @throws DependencyException + * @throws NotFoundException + * @throws FileNotFoundException + */ + public function testBackupFromEnvironmentVarIsSuccessful(): void + { + $this->setEnvironmentVariables(); + + $commandTester = $this->executeCommandTest( + BackupCommand::class, + null, + false + ); + + // the output of the command in the console + $output = $commandTester->getDisplay(); + $this->assertStringContainsString('Application and database backup completed successfully', $output); + + $this->checkBackupFilesAreCreated(); + + // Recreate cache directory to avoid unwanted behavior + recreateDir(CACHE_PATH); + } + + private function setEnvironmentVariables(): void + { + putenv(sprintf('%s=%s', + BackupCommand::$envVarsMapping['path'], + TMP_PATH) + ); + } +} diff --git a/tests/SP/Modules/Cli/Commands/InstallCommandTest.php b/tests/SP/Modules/Cli/Commands/InstallCommandTest.php index df96c908..7fc4293d 100644 --- a/tests/SP/Modules/Cli/Commands/InstallCommandTest.php +++ b/tests/SP/Modules/Cli/Commands/InstallCommandTest.php @@ -32,7 +32,6 @@ use SP\Modules\Cli\Commands\InstallCommand; use SP\Storage\Database\DatabaseException; use SP\Tests\DatabaseUtil; use SP\Tests\Modules\Cli\CliTestCase; -use Symfony\Component\Console\Tester\CommandTester; use function SP\Tests\getResource; use function SP\Tests\recreateDir; use function SP\Tests\saveResource; @@ -45,11 +44,11 @@ class InstallCommandTest extends CliTestCase /** * @var string */ - protected static $currentConfig; + protected static string $currentConfig; /** * @var string[] */ - private static $commandInputData = [ + protected static array $commandInputData = [ 'adminLogin' => 'Admin', 'databaseHost' => 'localhost', 'databaseName' => 'syspass-test-install', @@ -92,41 +91,13 @@ class InstallCommandTest extends CliTestCase */ public function testInstallationIsAborted(): void { - $commandTester = $this->executeCommandTest(); + $commandTester = $this->executeCommandTest(InstallCommand::class); // the output of the command in the console $output = $commandTester->getDisplay(); $this->assertStringContainsString('Installation aborted', $output); } - /** - * @param array|null $inputData - * @param bool $useInputData - * - * @return CommandTester - * @throws DependencyException - * @throws NotFoundException - */ - private function executeCommandTest( - ?array $inputData = null, - bool $useInputData = true - ): CommandTester - { - $installCommand = self::$dic->get(InstallCommand::class); - - if (null === $inputData && $useInputData) { - $inputData = self::$commandInputData; - } - - $commandTester = new CommandTester($installCommand); - $commandTester->execute( - $inputData ?? [], - ['interactive' => false] - ); - - return $commandTester; - } - /** * @throws DependencyException * @throws NotFoundException @@ -138,7 +109,10 @@ class InstallCommandTest extends CliTestCase ['--forceInstall' => null] ); - $commandTester = $this->executeCommandTest($inputData); + $commandTester = $this->executeCommandTest( + InstallCommand::class, + $inputData + ); // the output of the command in the console $output = $commandTester->getDisplay(); @@ -156,7 +130,10 @@ class InstallCommandTest extends CliTestCase ['--adminPassword' => ''] ); - $commandTester = $this->executeCommandTest($inputData); + $commandTester = $this->executeCommandTest( + InstallCommand::class, + $inputData + ); // the output of the command in the console $output = $commandTester->getDisplay(); @@ -174,7 +151,10 @@ class InstallCommandTest extends CliTestCase ['--masterPassword' => ''] ); - $commandTester = $this->executeCommandTest($inputData); + $commandTester = $this->executeCommandTest( + InstallCommand::class, + $inputData + ); // the output of the command in the console $output = $commandTester->getDisplay(); @@ -198,7 +178,10 @@ class InstallCommandTest extends CliTestCase ] ); - $commandTester = $this->executeCommandTest($inputData); + $commandTester = $this->executeCommandTest( + InstallCommand::class, + $inputData + ); // the output of the command in the console $output = $commandTester->getDisplay(); @@ -229,7 +212,10 @@ class InstallCommandTest extends CliTestCase ] ); - $commandTester = $this->executeCommandTest($inputData); + $commandTester = $this->executeCommandTest( + InstallCommand::class, + $inputData + ); // the output of the command in the console $output = $commandTester->getDisplay(); @@ -273,7 +259,10 @@ class InstallCommandTest extends CliTestCase ] ); - $commandTester = $this->executeCommandTest($inputData); + $commandTester = $this->executeCommandTest( + InstallCommand::class, + $inputData + ); // the output of the command in the console $output = $commandTester->getDisplay(); @@ -296,7 +285,11 @@ class InstallCommandTest extends CliTestCase { $this->setEnvironmentVariables(); - $commandTester = $this->executeCommandTest(null, false); + $commandTester = $this->executeCommandTest( + InstallCommand::class, + null, + false + ); // the output of the command in the console $output = $commandTester->getDisplay(); @@ -347,7 +340,11 @@ class InstallCommandTest extends CliTestCase $this->setEnvironmentVariables(); - $commandTester = $this->executeCommandTest(null, false); + $commandTester = $this->executeCommandTest( + InstallCommand::class, + null, + false + ); // the output of the command in the console $output = $commandTester->getDisplay(); @@ -370,7 +367,11 @@ class InstallCommandTest extends CliTestCase $this->setEnvironmentVariables(); - $commandTester = $this->executeCommandTest(null, false); + $commandTester = $this->executeCommandTest( + InstallCommand::class, + null, + false + ); // the output of the command in the console $output = $commandTester->getDisplay(); diff --git a/tests/SP/bootstrap.php b/tests/SP/bootstrap.php index 24f98b90..756ccac4 100644 --- a/tests/SP/bootstrap.php +++ b/tests/SP/bootstrap.php @@ -27,13 +27,16 @@ namespace SP\Tests; use DI\Container; use DI\ContainerBuilder; use Exception; +use RuntimeException; use SP\Core\Context\ContextException; use SP\Core\Context\ContextInterface; +use SP\Core\Exceptions\FileNotFoundException; use SP\DataModel\ProfileData; use SP\Services\User\UserLoginResponse; use SP\Storage\Database\DatabaseConnectionData; use SP\Storage\Database\DBStorageInterface; use SP\Storage\Database\MySQLHandler; +use SP\Util\FileUtil; define('DEBUG', true); @@ -46,11 +49,11 @@ define('CONFIG_PATH', RESOURCE_PATH . DIRECTORY_SEPARATOR . 'config'); define('CONFIG_FILE', CONFIG_PATH . DIRECTORY_SEPARATOR . 'config.xml'); define('ACTIONS_FILE', CONFIG_PATH . DIRECTORY_SEPARATOR . 'actions.xml'); -define('MODULES_PATH', APP_ROOT. DIRECTORY_SEPARATOR. 'app' . DIRECTORY_SEPARATOR . 'modules'); +define('MODULES_PATH', APP_ROOT . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'modules'); define('SQL_PATH', APP_ROOT . DIRECTORY_SEPARATOR . 'schemas'); define('CACHE_PATH', RESOURCE_PATH . DIRECTORY_SEPARATOR . 'cache'); define('TMP_PATH', TEST_ROOT . DIRECTORY_SEPARATOR . 'tmp'); - +define('BACKUP_PATH', TMP_PATH); define('XML_SCHEMA', APP_ROOT . DIRECTORY_SEPARATOR . 'schemas' . DIRECTORY_SEPARATOR . 'syspass.xsd'); @@ -189,19 +192,20 @@ function saveResource($dir, $file, $data): string /** * @param $dir + * + * @throws FileNotFoundException */ function recreateDir($dir) { - if (!is_dir($dir)) { - print 'Creating ' . $dir . PHP_EOL; - - if (!mkdir($dir) && !is_dir($dir)) { - throw new \RuntimeException(sprintf('Directory "%s" was not created', $dir)); - } - } else { + if (is_dir($dir)) { print 'Deleting ' . $dir . PHP_EOL; - // Delete tmp dir ... - array_map('unlink', glob($dir . DIRECTORY_SEPARATOR . '*')); + FileUtil::rmdir_recursive($dir); + } + + print 'Creating ' . $dir . PHP_EOL; + + if (!mkdir($dir) && !is_dir($dir)) { + throw new RuntimeException(sprintf('Directory "%s" was not created', $dir)); } } \ No newline at end of file