]> BookStack Code Mirror - system-cli/blob - tests/Commands/RestoreCommandTest.php
Updated dependancies, increased min. PHP version
[system-cli] / tests / Commands / RestoreCommandTest.php
1 <?php declare(strict_types=1);
2
3 namespace Tests\Commands;
4
5 use mysqli;
6 use Tests\TestCase;
7 use ZipArchive;
8
9 class RestoreCommandTest extends TestCase
10 {
11
12     public function test_restore_into_cwd_by_default_with_all_content_types()
13     {
14         $mysql = new mysqli('db', 'bookstack', 'bookstack', 'bookstack');
15         $mysql->query('CREATE TABLE xx_testing (labels varchar(255));');
16
17         $result = $mysql->query('SHOW TABLES LIKE \'zz_testing\';');
18         $this->assertEquals(0, mysqli_num_rows($result));
19
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');");
26         });
27
28         exec('cp -r /var/www/bookstack /var/www/bookstack-restore');
29         chdir('/var/www/bookstack-restore');
30
31         $result = $this->runCommand('restore', [
32             'backup-zip' => $zipFile,
33         ], ['yes', '1']); // This restore uses the existing (Non-backup) APP_URL
34
35         $result->dumpError();
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');
44
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));
49
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');
53
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);
58
59         $mysql->query("DROP TABLE zz_testing;");
60         exec('rm -rf /var/www/bookstack-restore');
61     }
62
63     public function test_restore_using_backup_env_url()
64     {
65         $zipFile = $this->buildZip(function (ZipArchive $zip) {
66             $zip->addFromString('.env', "APP_KEY=abc123\nAPP_URL=https://restore.example.com");
67         });
68
69         exec('cp -r /var/www/bookstack /var/www/bookstack-restore-backup-env');
70         chdir('/var/www/bookstack-restore-backup-env');
71
72         $result = $this->runCommand('restore', [
73             'backup-zip' => $zipFile,
74         ], ['yes', '0']); // This restore uses the old (Backup) APP_URL
75
76         $result->assertSuccessfulExit();
77         $result->assertStdoutContains('✔ .env Config File');
78         $result->assertStdoutContains('Restore operation complete!');
79
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);
83
84         exec('rm -rf /var/www/bookstack-restore-backup-env');
85     }
86
87     public function test_command_fails_on_zip_with_no_expected_contents()
88     {
89         $zipFile = $this->buildZip(function (ZipArchive $zip) {
90             $zip->addFromString('spaghetti', "Hello world!");
91         });
92
93         chdir('/var/www/bookstack');
94
95         $result = $this->runCommand('restore', [
96             'backup-zip' => $zipFile,
97         ]);
98
99         $result->assertErrorExit();
100         $result->assertStderrContains("Provided ZIP backup [{$zipFile}] does not have any expected restorable content.");
101     }
102
103     public function test_limited_restore_using_app_directory_option()
104     {
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!");
108         });
109
110         chdir('/home');
111
112         $result = $this->runCommand('restore', [
113             'backup-zip' => $zipFile,
114             '--app-directory' => '/var/www/bookstack'
115         ], ['yes']);
116
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!');
124
125         unlink('/var/www/bookstack/themes/hello.txt');
126         $mysql = new mysqli('db', 'bookstack', 'bookstack', 'bookstack');
127         $mysql->query("DROP TABLE zz_testing;");
128     }
129
130     public function test_restore_with_symlinked_content_folders()
131     {
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');
137         });
138
139         exec('cp -r /var/www/bookstack /var/www/bookstack-symlink-restore');
140         chdir('/var/www/bookstack-symlink-restore');
141         mkdir('/symlinks');
142
143         $symlinkPaths = ['public/uploads', 'storage/uploads', '.env', 'themes'];
144         foreach ($symlinkPaths as $path) {
145             $targetFile = str_replace('/', '-', $path);
146             $code = 0;
147             $output = null;
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);
150             if ($code !== 0) {
151                 $this->fail("Error when setting up symlinks");
152             }
153         }
154
155         $result = $this->runCommand('restore', [
156             'backup-zip' => $zipFile,
157         ], ['yes', '1']);
158
159         $result->assertSuccessfulExit();
160
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');
164
165         exec('rm -rf /var/www/bookstack-symlink-restore');
166         exec('rm -rf /symlinks');
167     }
168
169     protected function buildZip(callable $builder): string
170     {
171         $zipFile = tempnam(sys_get_temp_dir(), 'cli-test');
172         unlink($zipFile);
173
174         $testZip = new ZipArchive();
175         $testZip->open($zipFile, ZipArchive::CREATE);
176         $builder($testZip);
177         $testZip->close();
178
179         return $zipFile;
180     }
181 }