use Cli\Services\MySqlRunner;
use Cli\Services\ProgramRunner;
use Cli\Services\RequirementsValidator;
+use Exception;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use Symfony\Component\Console\Command\Command;
/**
* @throws CommandError
- * @throws \Exception
+ * @throws Exception
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
}
if (!$hasContent) {
- throw new CommandError("Provided ZIP backup [{$zipPath}] does not have any expected restore-able content.");
+ throw new CommandError("Provided ZIP backup [{$zipPath}] does not have any expected restorable content.");
}
$output->writeln("<info>The checked elements will be restored into [{$appDir}].</info>");
rename($extractDir . DIRECTORY_SEPARATOR . $folderSubPath, $fullAppFolderPath);
}
- protected function deleteDirectoryAndContents(string $dir)
+ protected function deleteDirectoryAndContents(string $dir): void
{
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
file_put_contents($dropSqlTempFile, $mysql->dropTablesSql());
$mysql->importSqlFile($dropSqlTempFile);
-
+ // Import MySQL dump
$mysql->importSqlFile($dbDump);
}
}
namespace Tests\Commands;
+use mysqli;
use Tests\TestCase;
class RestoreCommandTest extends TestCase
public function test_restore_into_cwd_by_default_with_all_content_types()
{
- $mysql = new \mysqli('db', 'bookstack', 'bookstack', 'bookstack');
+ $mysql = new mysqli('db', 'bookstack', 'bookstack', 'bookstack');
$mysql->query('CREATE TABLE xx_testing (labels varchar(255));');
$result = $mysql->query('SHOW TABLES LIKE \'zz_testing\';');
$result->dumpError();
$result->assertSuccessfulExit();
+ $result->assertStdoutContains('✔ .env Config File');
+ $result->assertStdoutContains('✔ Themes Folder');
+ $result->assertStdoutContains('✔ Public File Uploads');
+ $result->assertStdoutContains('✔ Private File Uploads');
+ $result->assertStdoutContains('✔ Database Dump');
$result->assertStdoutContains('Restore operation complete!');
$result = $mysql->query('SELECT * FROM zz_testing where names = \'barry\';');
exec('rm -rf /var/www/bookstack-restore');
}
+ public function test_command_fails_on_zip_with_no_expected_contents()
+ {
+ $zipFile = $this->buildZip(function (\ZipArchive $zip) {
+ $zip->addFromString('spaghetti', "Hello world!");
+ });
+
+ chdir('/var/www/bookstack');
+
+ $result = $this->runCommand('restore', [
+ 'backup-zip' => $zipFile,
+ ]);
+
+ $result->assertErrorExit();
+ $result->assertStderrContains("Provided ZIP backup [{$zipFile}] does not have any expected restorable content.");
+ }
+
+ public function test_limited_restore_using_app_directory_option()
+ {
+ $zipFile = $this->buildZip(function (\ZipArchive $zip) {
+ $zip->addFromString('db.sql', "CREATE TABLE zz_testing (names varchar(255));");
+ $zip->addFromString('themes/hello.txt', "limited restore test!");
+ });
+
+ chdir('/home');
+
+ $result = $this->runCommand('restore', [
+ 'backup-zip' => $zipFile,
+ '--app-directory' => '/var/www/bookstack'
+ ], ['yes']);
+
+ $result->assertSuccessfulExit();
+ $result->assertStdoutContains('❌ .env Config File');
+ $result->assertStdoutContains('✔ Themes Folder');
+ $result->assertStdoutContains('❌ Public File Uploads');
+ $result->assertStdoutContains('❌ Private File Uploads');
+ $result->assertStdoutContains('✔ Database Dump');
+ $this->assertStringEqualsFile('/var/www/bookstack/themes/hello.txt', 'limited restore test!');
+
+ unlink('/var/www/bookstack/themes/hello.txt');
+ $mysql = new mysqli('db', 'bookstack', 'bookstack', 'bookstack');
+ $mysql->query("DROP TABLE zz_testing;");
+ }
+
protected function buildZip(callable $builder): string
{
$zipFile = tempnam(sys_get_temp_dir(), 'cli-test');