1 <?php declare(strict_types=1);
3 namespace Tests\Commands;
9 class RestoreCommandTest extends TestCase
12 public function test_restore_into_cwd_by_default_with_all_content_types()
14 $mysql = new mysqli('db', 'bookstack', 'bookstack', 'bookstack');
15 $mysql->query('CREATE TABLE xx_testing (labels varchar(255));');
17 $result = $mysql->query('SHOW TABLES LIKE \'zz_testing\';');
18 $this->assertEquals(0, mysqli_num_rows($result));
20 $zipFile = $this->buildZip(function (ZipArchive $zip) {
21 $zip->addFromString('.env', "APP_KEY=abc123\nAPP_URL=https://restore.example.com");
22 $zip->addFromString('public/uploads/test.txt', 'hello-public-uploads');
23 $zip->addFromString('storage/uploads/test.txt', 'hello-storage-uploads');
24 $zip->addFromString('themes/test.txt', 'hello-themes');
25 $zip->addFromString('db.sql', "CREATE TABLE zz_testing (names varchar(255));\nINSERT INTO zz_testing values ('barry');");
28 exec('cp -r /var/www/bookstack /var/www/bookstack-restore');
29 chdir('/var/www/bookstack-restore');
31 $result = $this->runCommand('restore', [
32 'backup-zip' => $zipFile,
33 ], ['yes', '1']); // This restore uses the existing (Non-backup) APP_URL
36 $result->assertSuccessfulExit();
37 $result->assertStdoutContains('✔ .env Config File');
38 $result->assertStdoutContains('✔ Themes Folder');
39 $result->assertStdoutContains('✔ Public File Uploads');
40 $result->assertStdoutContains('✔ Private File Uploads');
41 $result->assertStdoutContains('✔ Database Dump');
42 $result->assertStdoutContains('Restore operation complete!');
43 $result->assertStdoutContains('App URL change made, updating database with URL change');
45 $result = $mysql->query('SELECT * FROM zz_testing where names = \'barry\';');
46 $this->assertEquals(1, mysqli_num_rows($result));
47 $result = $mysql->query('SHOW TABLES LIKE \'xx_testing\';');
48 $this->assertEquals(0, mysqli_num_rows($result));
50 $this->assertStringEqualsFile('/var/www/bookstack-restore/public/uploads/test.txt', 'hello-public-uploads');
51 $this->assertStringEqualsFile('/var/www/bookstack-restore/storage/uploads/test.txt', 'hello-storage-uploads');
52 $this->assertStringEqualsFile('/var/www/bookstack-restore/themes/test.txt', 'hello-themes');
54 $env = file_get_contents('/var/www/bookstack-restore/.env');
55 $this->assertStringContainsString('APP_KEY=abc123', $env);
56 $this->assertStringNotContainsString('APP_URL=https://restore.example.com', $env);
57 $this->assertStringContainsString('APP_URL="https://example.com"', $env);
59 $mysql->query("DROP TABLE zz_testing;");
60 exec('rm -rf /var/www/bookstack-restore');
63 public function test_restore_using_backup_env_url()
65 $zipFile = $this->buildZip(function (ZipArchive $zip) {
66 $zip->addFromString('.env', "APP_KEY=abc123\nAPP_URL=https://restore.example.com");
69 exec('cp -r /var/www/bookstack /var/www/bookstack-restore-backup-env');
70 chdir('/var/www/bookstack-restore-backup-env');
72 $result = $this->runCommand('restore', [
73 'backup-zip' => $zipFile,
74 ], ['yes', '0']); // This restore uses the old (Backup) APP_URL
76 $result->assertSuccessfulExit();
77 $result->assertStdoutContains('✔ .env Config File');
78 $result->assertStdoutContains('Restore operation complete!');
80 $env = file_get_contents('/var/www/bookstack-restore-backup-env/.env');
81 $this->assertStringContainsString('APP_KEY=abc123', $env);
82 $this->assertStringContainsString('APP_URL="https://restore.example.com"', $env);
84 exec('rm -rf /var/www/bookstack-restore-backup-env');
87 public function test_command_fails_on_zip_with_no_expected_contents()
89 $zipFile = $this->buildZip(function (ZipArchive $zip) {
90 $zip->addFromString('spaghetti', "Hello world!");
93 chdir('/var/www/bookstack');
95 $result = $this->runCommand('restore', [
96 'backup-zip' => $zipFile,
99 $result->assertErrorExit();
100 $result->assertStderrContains("Provided ZIP backup [{$zipFile}] does not have any expected restorable content.");
103 public function test_limited_restore_using_app_directory_option()
105 $zipFile = $this->buildZip(function (ZipArchive $zip) {
106 $zip->addFromString('db.sql', "CREATE TABLE zz_testing (names varchar(255));");
107 $zip->addFromString('themes/hello.txt', "limited restore test!");
112 $result = $this->runCommand('restore', [
113 'backup-zip' => $zipFile,
114 '--app-directory' => '/var/www/bookstack'
117 $result->assertSuccessfulExit();
118 $result->assertStdoutContains('❌ .env Config File');
119 $result->assertStdoutContains('✔ Themes Folder');
120 $result->assertStdoutContains('❌ Public File Uploads');
121 $result->assertStdoutContains('❌ Private File Uploads');
122 $result->assertStdoutContains('✔ Database Dump');
123 $this->assertStringEqualsFile('/var/www/bookstack/themes/hello.txt', 'limited restore test!');
125 unlink('/var/www/bookstack/themes/hello.txt');
126 $mysql = new mysqli('db', 'bookstack', 'bookstack', 'bookstack');
127 $mysql->query("DROP TABLE zz_testing;");
130 public function test_restore_with_symlinked_content_folders()
132 $zipFile = $this->buildZip(function (ZipArchive $zip) {
133 $zip->addFromString('.env', "APP_KEY=abc123\nAPP_URL=https://example.com");
134 $zip->addFromString('public/uploads/test.txt', 'hello-public-uploads');
135 $zip->addFromString('storage/uploads/test.txt', 'hello-storage-uploads');
136 $zip->addFromString('themes/test.txt', 'hello-themes');
139 exec('cp -r /var/www/bookstack /var/www/bookstack-symlink-restore');
140 chdir('/var/www/bookstack-symlink-restore');
143 $symlinkPaths = ['public/uploads', 'storage/uploads', '.env', 'themes'];
144 foreach ($symlinkPaths as $path) {
145 $targetFile = str_replace('/', '-', $path);
148 exec("mv /var/www/bookstack-symlink-restore/{$path} /symlinks/{$targetFile}", $output, $code);
149 exec("ln -s /symlinks/{$targetFile} /var/www/bookstack-symlink-restore/{$path}", $output, $code);
151 $this->fail("Error when setting up symlinks");
155 $result = $this->runCommand('restore', [
156 'backup-zip' => $zipFile,
159 $result->assertSuccessfulExit();
161 $this->assertStringEqualsFile('/var/www/bookstack-symlink-restore/public/uploads/test.txt', 'hello-public-uploads');
162 $this->assertStringEqualsFile('/var/www/bookstack-symlink-restore/storage/uploads/test.txt', 'hello-storage-uploads');
163 $this->assertStringEqualsFile('/var/www/bookstack-symlink-restore/themes/test.txt', 'hello-themes');
165 exec('rm -rf /var/www/bookstack-symlink-restore');
166 exec('rm -rf /symlinks');
169 protected function buildZip(callable $builder): string
171 $zipFile = tempnam(sys_get_temp_dir(), 'cli-test');
174 $testZip = new ZipArchive();
175 $testZip->open($zipFile, ZipArchive::CREATE);