]> BookStack Code Mirror - system-cli/blob - tests/Commands/RestoreCommandTest.php
Added support for key restore files/folders being symlinks
[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
8 class RestoreCommandTest extends TestCase
9 {
10
11     public function test_restore_into_cwd_by_default_with_all_content_types()
12     {
13         $mysql = new mysqli('db', 'bookstack', 'bookstack', 'bookstack');
14         $mysql->query('CREATE TABLE xx_testing (labels varchar(255));');
15
16         $result = $mysql->query('SHOW TABLES LIKE \'zz_testing\';');
17         $this->assertEquals(0, mysqli_num_rows($result));
18
19         $zipFile = $this->buildZip(function (\ZipArchive $zip) {
20             $zip->addFromString('.env', "APP_KEY=abc123\nAPP_URL=https://example.com");
21             $zip->addFromString('public/uploads/test.txt', 'hello-public-uploads');
22             $zip->addFromString('storage/uploads/test.txt', 'hello-storage-uploads');
23             $zip->addFromString('themes/test.txt', 'hello-themes');
24             $zip->addFromString('db.sql', "CREATE TABLE zz_testing (names varchar(255));\nINSERT INTO zz_testing values ('barry');");
25         });
26
27         exec('cp -r /var/www/bookstack /var/www/bookstack-restore');
28         chdir('/var/www/bookstack-restore');
29
30         $result = $this->runCommand('restore', [
31             'backup-zip' => $zipFile,
32         ], ['yes', '1']);
33
34         $result->assertSuccessfulExit();
35         $result->assertStdoutContains('✔ .env Config File');
36         $result->assertStdoutContains('✔ Themes Folder');
37         $result->assertStdoutContains('✔ Public File Uploads');
38         $result->assertStdoutContains('✔ Private File Uploads');
39         $result->assertStdoutContains('✔ Database Dump');
40         $result->assertStdoutContains('Restore operation complete!');
41
42         $result = $mysql->query('SELECT * FROM zz_testing where names = \'barry\';');
43         $this->assertEquals(1, mysqli_num_rows($result));
44         $result = $mysql->query('SHOW TABLES LIKE \'xx_testing\';');
45         $this->assertEquals(0, mysqli_num_rows($result));
46
47         $this->assertStringEqualsFile('/var/www/bookstack-restore/public/uploads/test.txt', 'hello-public-uploads');
48         $this->assertStringEqualsFile('/var/www/bookstack-restore/storage/uploads/test.txt', 'hello-storage-uploads');
49         $this->assertStringEqualsFile('/var/www/bookstack-restore/themes/test.txt', 'hello-themes');
50
51         $mysql->query("DROP TABLE zz_testing;");
52         exec('rm -rf /var/www/bookstack-restore');
53     }
54
55     public function test_command_fails_on_zip_with_no_expected_contents()
56     {
57         $zipFile = $this->buildZip(function (\ZipArchive $zip) {
58             $zip->addFromString('spaghetti', "Hello world!");
59         });
60
61         chdir('/var/www/bookstack');
62
63         $result = $this->runCommand('restore', [
64             'backup-zip' => $zipFile,
65         ]);
66
67         $result->assertErrorExit();
68         $result->assertStderrContains("Provided ZIP backup [{$zipFile}] does not have any expected restorable content.");
69     }
70
71     public function test_limited_restore_using_app_directory_option()
72     {
73         $zipFile = $this->buildZip(function (\ZipArchive $zip) {
74             $zip->addFromString('db.sql', "CREATE TABLE zz_testing (names varchar(255));");
75             $zip->addFromString('themes/hello.txt', "limited restore test!");
76         });
77
78         chdir('/home');
79
80         $result = $this->runCommand('restore', [
81             'backup-zip' => $zipFile,
82             '--app-directory' => '/var/www/bookstack'
83         ], ['yes']);
84
85         $result->assertSuccessfulExit();
86         $result->assertStdoutContains('❌ .env Config File');
87         $result->assertStdoutContains('✔ Themes Folder');
88         $result->assertStdoutContains('❌ Public File Uploads');
89         $result->assertStdoutContains('❌ Private File Uploads');
90         $result->assertStdoutContains('✔ Database Dump');
91         $this->assertStringEqualsFile('/var/www/bookstack/themes/hello.txt', 'limited restore test!');
92
93         unlink('/var/www/bookstack/themes/hello.txt');
94         $mysql = new mysqli('db', 'bookstack', 'bookstack', 'bookstack');
95         $mysql->query("DROP TABLE zz_testing;");
96     }
97
98     public function test_restore_with_symlinked_content_folders()
99     {
100         $zipFile = $this->buildZip(function (\ZipArchive $zip) {
101             $zip->addFromString('.env', "APP_KEY=abc123\nAPP_URL=https://example.com");
102             $zip->addFromString('public/uploads/test.txt', 'hello-public-uploads');
103             $zip->addFromString('storage/uploads/test.txt', 'hello-storage-uploads');
104             $zip->addFromString('themes/test.txt', 'hello-themes');
105         });
106
107         exec('cp -r /var/www/bookstack /var/www/bookstack-symlink-restore');
108         chdir('/var/www/bookstack-symlink-restore');
109         mkdir('/symlinks');
110
111         $symlinkPaths = ['public/uploads', 'storage/uploads', '.env', 'themes'];
112         foreach ($symlinkPaths as $path) {
113             $targetFile = str_replace('/', '-', $path);
114             $code = 0;
115             $output = null;
116             exec("mv /var/www/bookstack-symlink-restore/{$path} /symlinks/{$targetFile}", $output, $code);
117             exec("ln -s /symlinks/{$targetFile} /var/www/bookstack-symlink-restore/{$path}", $output, $code);
118             if ($code !== 0) {
119                 $this->fail("Error when setting up symlinks");
120             }
121         }
122
123         $result = $this->runCommand('restore', [
124             'backup-zip' => $zipFile,
125         ], ['yes', '1']);
126
127         $result->assertSuccessfulExit();
128
129         $this->assertStringEqualsFile('/var/www/bookstack-symlink-restore/public/uploads/test.txt', 'hello-public-uploads');
130         $this->assertStringEqualsFile('/var/www/bookstack-symlink-restore/storage/uploads/test.txt', 'hello-storage-uploads');
131         $this->assertStringEqualsFile('/var/www/bookstack-symlink-restore/themes/test.txt', 'hello-themes');
132
133         exec('rm -rf /var/www/bookstack-symlink-restore');
134     }
135
136     protected function buildZip(callable $builder): string
137     {
138         $zipFile = tempnam(sys_get_temp_dir(), 'cli-test');
139         $testZip = new \ZipArchive('');
140         $testZip->open($zipFile);
141         $builder($testZip);
142         $testZip->close();
143
144         return $zipFile;
145     }
146 }