]> BookStack Code Mirror - system-cli/blob - tests/Commands/BackupCommandTest.php
DownloadVendorCommand: Added check for ZIP file access
[system-cli] / tests / Commands / BackupCommandTest.php
1 <?php declare(strict_types=1);
2
3 namespace Tests\Commands;
4
5 use Tests\TestCase;
6
7 class BackupCommandTest extends TestCase
8 {
9     static string $uniqueUserEmail = '';
10
11     public static function setUpBeforeClass(): void
12     {
13         static::$uniqueUserEmail = bin2hex(random_bytes(10)) . '@example.com';
14         chdir('/var/www/bookstack');
15         // Ensure the database is created and create an admin user we can look out for in the data.
16         exec('php artisan migrate --force');
17         exec('php artisan bookstack:create-admin --email="' . static::$uniqueUserEmail . '" --name="Bazza" --password="hunter200"');
18     }
19
20     public function test_command_does_full_backup_of_cwd_instance_by_default()
21     {
22         chdir('/var/www/bookstack');
23         $this->assertCount(0, glob('storage/backups/bookstack-backup-*.zip'));
24
25         file_put_contents('/var/www/bookstack/themes/test.txt', static::$uniqueUserEmail . '-themes');
26         file_put_contents('/var/www/bookstack/public/uploads/test.txt', static::$uniqueUserEmail . '-public-uploads');
27         file_put_contents('/var/www/bookstack/storage/uploads/test.txt', static::$uniqueUserEmail . '-storage-uploads');
28
29         $result = $this->runCommand('backup');
30         $result->assertSuccessfulExit();
31         $result->assertStdoutContains("Backup finished.");
32
33         $this->assertCount(1, glob('storage/backups/bookstack-backup-*.zip'));
34         $zipFile = glob('storage/backups/bookstack-backup-*.zip')[0];
35
36         $zip = new \ZipArchive();
37         $zip->open($zipFile);
38         $dbDump = $zip->getFromName('db.sql');
39         $this->assertStringContainsString('APP_KEY=', $zip->getFromName('.env'));
40         $this->assertStringContainsString(static::$uniqueUserEmail, $dbDump);
41         $this->assertStringContainsString('page_revisions', $dbDump);
42         $this->assertStringContainsString(static::$uniqueUserEmail . '-public-uploads', $zip->getFromName('public/uploads/test.txt'));
43         $this->assertStringContainsString(static::$uniqueUserEmail . '-storage-uploads', $zip->getFromName('storage/uploads/test.txt'));
44         $this->assertStringContainsString(static::$uniqueUserEmail . '-themes', $zip->getFromName('themes/test.txt'));
45
46         unlink($zipFile);
47     }
48
49     public function test_no_options()
50     {
51         chdir('/var/www/bookstack');
52         $this->assertCount(0, glob('bookstack-backup-*.zip'));
53
54         $result = $this->runCommand('backup', [
55             '--no-database' => true,
56             '--no-uploads' => true,
57             '--no-themes' => true,
58         ]);
59         $result->assertSuccessfulExit();
60
61         $zipFile = glob('storage/backups/bookstack-backup-*.zip')[0];
62
63         $zip = new \ZipArchive();
64         $zip->open($zipFile);
65         $this->assertLessThan(3, $zip->numFiles);
66         $this->assertFalse($zip->getFromName('db.sql'));
67         $this->assertFalse($zip->getFromName('themes/.gitignore'));
68         $this->assertFalse($zip->getFromName('public/uploads/.gitignore'));
69         $this->assertFalse($zip->getFromName('storage/uploads/.gitignore'));
70
71         unlink($zipFile);
72     }
73
74     public function test_app_directory_option()
75     {
76         chdir('/var');
77         $this->assertCount(0, glob('bookstack-backup-*.zip'));
78
79         $result = $this->runCommand('backup', [
80             '--no-database' => true,
81             '--no-uploads' => true,
82             '--no-themes' => true,
83             '--app-directory' => '/var/www/bookstack',
84             'backup-path' => './'
85         ]);
86         $result->assertSuccessfulExit();
87
88         $zipFile = glob('bookstack-backup-*.zip')[0] ?? null;
89         $this->assertNotNull($zipFile);
90
91         unlink($zipFile);
92     }
93
94     public function test_backup_path_argument()
95     {
96         chdir('/var/www/bookstack');
97         $this->assertCount(0, glob('/home/bookstack-backup-*.zip'));
98         $this->assertFileDoesNotExist('/home/my-cool-backup.zip');
99
100         $result = $this->runCommand('backup', [
101             'backup-path' => '/home/my-cool-backup.zip',
102             '--no-database' => true,
103             '--no-uploads' => true,
104             '--no-themes' => true,
105         ]);
106         $result->assertSuccessfulExit();
107         $this->assertFileExists('/home/my-cool-backup.zip');
108         unlink('/home/my-cool-backup.zip');
109
110         $result = $this->runCommand('backup', [
111             'backup-path' => '/home/',
112             '--no-database' => true,
113             '--no-uploads' => true,
114             '--no-themes' => true,
115         ]);
116         $result->assertSuccessfulExit();
117         $this->assertCount(1, glob('/home/bookstack-backup-*.zip'));
118         $zipFile = glob('/home/bookstack-backup-*.zip')[0];
119         unlink($zipFile);
120     }
121
122     public function test_command_resolves_nested_symlinks()
123     {
124         $symDirs = ['storage/uploads/files', 'storage/uploads/images'];
125         exec('cp -r /var/www/bookstack /var/www/bookstack-symlink-backup');
126         mkdir('/symlinks');
127         foreach ($symDirs as $dir) {
128             $targetFile = str_replace('/', '-', $dir);
129             $code = 0;
130             $output = null;
131             exec("mkdir -p /var/www/bookstack-symlink-backup/{$dir}", $output, $code);
132             exec("mv /var/www/bookstack-symlink-backup/{$dir} /symlinks/{$targetFile}", $output, $code);
133             exec("ln -s /symlinks/{$targetFile} /var/www/bookstack-symlink-backup/{$dir}", $output, $code);
134             file_put_contents("/symlinks/{$targetFile}/test.txt", "Hello from $dir");
135             if ($code !== 0) {
136                 $this->fail("Error when setting up symlinks");
137             }
138         }
139
140         chdir('/var/www/bookstack-symlink-backup');
141         $this->assertCount(0, glob('storage/backups/bookstack-backup-*.zip'));
142         $result = $this->runCommand('backup');
143         $result->assertSuccessfulExit();
144         $this->assertCount(1, glob('storage/backups/bookstack-backup-*.zip'));
145         $zipFile = glob('storage/backups/bookstack-backup-*.zip')[0];
146
147         $zip = new \ZipArchive();
148         $zip->open($zipFile);
149         foreach ($symDirs as $dir) {
150             $fileData = $zip->getFromName("{$dir}/test.txt");
151             $this->assertNotFalse($fileData);
152             $this->assertStringContainsString("Hello from {$dir}", $fileData);
153         }
154         $zip->close();
155
156         exec('rm -rf /symlinks');
157         exec('rm -rf /var/www/bookstack-symlink-backup');
158     }
159
160 }