]> git.mxchange.org Git - friendica.git/blob - tests/src/Core/InstallerTest.php
Merge pull request #8077 from annando/notifications
[friendica.git] / tests / src / Core / InstallerTest.php
1 <?php
2
3 // this is in the same namespace as Install for mocking 'function_exists'
4 namespace Friendica\Core;
5
6 use Dice\Dice;
7 use Friendica\Core\Config\Cache\ConfigCache;
8 use Friendica\DI;
9 use Friendica\Network\CurlResult;
10 use Friendica\Test\MockedTest;
11 use Friendica\Test\Util\VFSTrait;
12 use Friendica\Util\Network;
13 use Mockery\MockInterface;
14
15 class InstallerTest extends MockedTest
16 {
17         use VFSTrait;
18
19         /**
20          * @var \Friendica\Core\L10n\L10n|MockInterface
21          */
22         private $l10nMock;
23
24         public function setUp()
25         {
26                 parent::setUp();
27
28                 $this->setUpVfsDir();
29
30                 $this->l10nMock = \Mockery::mock(\Friendica\Core\L10n\L10n::class);
31
32                 /** @var Dice|MockInterface $dice */
33                 $dice = \Mockery::mock(Dice::class)->makePartial();
34                 $dice = $dice->addRules(include __DIR__ . '/../../../static/dependencies.config.php');
35
36                 $dice->shouldReceive('create')
37                            ->with(\Friendica\Core\L10n\L10n::class, [])
38                            ->andReturn($this->l10nMock);
39
40                 DI::init($dice);
41         }
42
43         private function mockL10nT(string $text, $times = null)
44         {
45                 $this->l10nMock->shouldReceive('t')->with($text)->andReturn($text)->times($times);
46         }
47
48         /**
49          * Mocking the L10n::t() calls for the function checks
50          */
51         private function mockFunctionL10TCalls()
52         {
53                 $this->mockL10nT('Apache mod_rewrite module', 1);
54                 $this->mockL10nT('PDO or MySQLi PHP module', 1);
55                 $this->mockL10nT('libCurl PHP module', 1);
56                 $this->mockL10nT('Error: libCURL PHP module required but not installed.', 1);
57                 $this->mockL10nT('XML PHP module', 1);
58                 $this->mockL10nT('GD graphics PHP module', 1);
59                 $this->mockL10nT('Error: GD graphics PHP module with JPEG support required but not installed.', 1);
60                 $this->mockL10nT('OpenSSL PHP module', 1);
61                 $this->mockL10nT('Error: openssl PHP module required but not installed.', 1);
62                 $this->mockL10nT('mb_string PHP module', 1);
63                 $this->mockL10nT('Error: mb_string PHP module required but not installed.', 1);
64                 $this->mockL10nT('iconv PHP module', 1);
65                 $this->mockL10nT('Error: iconv PHP module required but not installed.', 1);
66                 $this->mockL10nT('POSIX PHP module', 1);
67                 $this->mockL10nT('Error: POSIX PHP module required but not installed.', 1);
68                 $this->mockL10nT('JSON PHP module', 1);
69                 $this->mockL10nT('Error: JSON PHP module required but not installed.', 1);
70                 $this->mockL10nT('File Information PHP module', 1);
71                 $this->mockL10nT('Error: File Information PHP module required but not installed.', 1);
72         }
73
74         private function assertCheckExist($position, $title, $help, $status, $required, $assertionArray)
75         {
76                 $subSet = [$position => [
77                         'title' => $title,
78                         'status' => $status,
79                         'required' => $required,
80                         'error_msg' => null,
81                         'help' => $help]
82                 ];
83
84                 $this->assertArraySubset($subSet, $assertionArray, false, "expected subset: " . PHP_EOL . print_r($subSet, true) . PHP_EOL . "current subset: " . print_r($assertionArray, true));
85         }
86
87         /**
88          * Replaces function_exists results with given mocks
89          *
90          * @param array $functions a list from function names and their result
91          */
92         private function setFunctions($functions)
93         {
94                 global $phpMock;
95                 $phpMock['function_exists'] = function($function) use ($functions) {
96                         foreach ($functions as $name => $value) {
97                                 if ($function == $name) {
98                                         return $value;
99                                 }
100                         }
101                         return '__phpunit_continue__';
102                 };
103         }
104
105         /**
106          * Replaces class_exist results with given mocks
107          *
108          * @param array $classes a list from class names and their results
109          */
110         private function setClasses($classes)
111         {
112                 global $phpMock;
113                 $phpMock['class_exists'] = function($class) use ($classes) {
114                         foreach ($classes as $name => $value) {
115                                 if ($class == $name) {
116                                         return $value;
117                                 }
118                         }
119                         return '__phpunit_continue__';
120                 };
121         }
122
123         /**
124          * @small
125          */
126         public function testCheckKeys()
127         {
128                 $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
129
130                 $this->setFunctions(['openssl_pkey_new' => false]);
131                 $install = new Installer();
132                 $this->assertFalse($install->checkKeys());
133
134                 $this->setFunctions(['openssl_pkey_new' => true]);
135                 $install = new Installer();
136                 $this->assertTrue($install->checkKeys());
137         }
138
139         /**
140          * @small
141          */
142         public function testCheckFunctions()
143         {
144                 $this->mockFunctionL10TCalls();
145                 $this->setFunctions(['curl_init' => false, 'imagecreatefromjpeg' => true]);
146                 $install = new Installer();
147                 $this->assertFalse($install->checkFunctions());
148                 $this->assertCheckExist(3,
149                         'libCurl PHP module',
150                         'Error: libCURL PHP module required but not installed.',
151                         false,
152                         true,
153                         $install->getChecks());
154
155                 $this->mockFunctionL10TCalls();
156                 $this->setFunctions(['imagecreatefromjpeg' => false]);
157                 $install = new Installer();
158                 $this->assertFalse($install->checkFunctions());
159                 $this->assertCheckExist(4,
160                         'GD graphics PHP module',
161                         'Error: GD graphics PHP module with JPEG support required but not installed.',
162                         false,
163                         true,
164                         $install->getChecks());
165
166                 $this->mockFunctionL10TCalls();
167                 $this->setFunctions(['openssl_public_encrypt' => false]);
168                 $install = new Installer();
169                 $this->assertFalse($install->checkFunctions());
170                 $this->assertCheckExist(5,
171                         'OpenSSL PHP module',
172                         'Error: openssl PHP module required but not installed.',
173                         false,
174                         true,
175                         $install->getChecks());
176
177                 $this->mockFunctionL10TCalls();
178                 $this->setFunctions(['mb_strlen' => false]);
179                 $install = new Installer();
180                 $this->assertFalse($install->checkFunctions());
181                 $this->assertCheckExist(6,
182                         'mb_string PHP module',
183                         'Error: mb_string PHP module required but not installed.',
184                         false,
185                         true,
186                         $install->getChecks());
187
188                 $this->mockFunctionL10TCalls();
189                 $this->setFunctions(['iconv_strlen' => false]);
190                 $install = new Installer();
191                 $this->assertFalse($install->checkFunctions());
192                 $this->assertCheckExist(7,
193                         'iconv PHP module',
194                         'Error: iconv PHP module required but not installed.',
195                         false,
196                         true,
197                         $install->getChecks());
198
199                 $this->mockFunctionL10TCalls();
200                 $this->setFunctions(['posix_kill' => false]);
201                 $install = new Installer();
202                 $this->assertFalse($install->checkFunctions());
203                 $this->assertCheckExist(8,
204                         'POSIX PHP module',
205                         'Error: POSIX PHP module required but not installed.',
206                         false,
207                         true,
208                         $install->getChecks());
209
210                 $this->mockFunctionL10TCalls();
211                 $this->setFunctions(['json_encode' => false]);
212                 $install = new Installer();
213                 $this->assertFalse($install->checkFunctions());
214                 $this->assertCheckExist(9,
215                         'JSON PHP module',
216                         'Error: JSON PHP module required but not installed.',
217                         false,
218                         true,
219                         $install->getChecks());
220
221                 $this->mockFunctionL10TCalls();
222                 $this->setFunctions(['finfo_open' => false]);
223                 $install = new Installer();
224                 $this->assertFalse($install->checkFunctions());
225                 $this->assertCheckExist(10,
226                         'File Information PHP module',
227                         'Error: File Information PHP module required but not installed.',
228                         false,
229                         true,
230                         $install->getChecks());
231
232                 $this->mockFunctionL10TCalls();
233                 $this->setFunctions([
234                         'curl_init' => true,
235                         'imagecreatefromjpeg' => true,
236                         'openssl_public_encrypt' => true,
237                         'mb_strlen' => true,
238                         'iconv_strlen' => true,
239                         'posix_kill' => true,
240                         'json_encode' => true,
241                         'finfo_open' => true,
242                 ]);
243                 $install = new Installer();
244                 $this->assertTrue($install->checkFunctions());
245         }
246
247         /**
248          * @small
249          */
250         public function testCheckLocalIni()
251         {
252                 $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
253
254                 $this->assertTrue($this->root->hasChild('config/local.config.php'));
255
256                 $install = new Installer();
257                 $this->assertTrue($install->checkLocalIni());
258
259                 $this->delConfigFile('local.config.php');
260
261                 $this->assertFalse($this->root->hasChild('config/local.config.php'));
262
263                 $install = new Installer();
264                 $this->assertTrue($install->checkLocalIni());
265         }
266
267         /**
268          * @small
269          * @runInSeparateProcess
270          * @preserveGlobalState disabled
271          */
272         public function testCheckHtAccessFail()
273         {
274                 $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
275
276                 // Mocking the CURL Response
277                 $curlResult = \Mockery::mock(CurlResult::class);
278                 $curlResult
279                         ->shouldReceive('getReturnCode')
280                         ->andReturn('404');
281                 $curlResult
282                         ->shouldReceive('getRedirectUrl')
283                         ->andReturn('');
284                 $curlResult
285                         ->shouldReceive('getError')
286                         ->andReturn('test Error');
287
288                 // Mocking the CURL Request
289                 $networkMock = \Mockery::mock('alias:' . Network::class);
290                 $networkMock
291                         ->shouldReceive('fetchUrlFull')
292                         ->with('https://test/install/testrewrite')
293                         ->andReturn($curlResult);
294                 $networkMock
295                         ->shouldReceive('fetchUrlFull')
296                         ->with('http://test/install/testrewrite')
297                         ->andReturn($curlResult);
298
299                 // Mocking that we can use CURL
300                 $this->setFunctions(['curl_init' => true]);
301
302                 $install = new Installer();
303
304                 $this->assertFalse($install->checkHtAccess('https://test'));
305                 $this->assertSame('test Error', $install->getChecks()[0]['error_msg']['msg']);
306         }
307
308         /**
309          * @small
310          * @runInSeparateProcess
311          * @preserveGlobalState disabled
312          */
313         public function testCheckHtAccessWork()
314         {
315                 $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
316
317                 // Mocking the failed CURL Response
318                 $curlResultF = \Mockery::mock(CurlResult::class);
319                 $curlResultF
320                         ->shouldReceive('getReturnCode')
321                         ->andReturn('404');
322
323                 // Mocking the working CURL Response
324                 $curlResultW = \Mockery::mock(CurlResult::class);
325                 $curlResultW
326                         ->shouldReceive('getReturnCode')
327                         ->andReturn('204');
328
329                 // Mocking the CURL Request
330                 $networkMock = \Mockery::mock('alias:' . Network::class);
331                 $networkMock
332                         ->shouldReceive('fetchUrlFull')
333                         ->with('https://test/install/testrewrite')
334                         ->andReturn($curlResultF);
335                 $networkMock
336                         ->shouldReceive('fetchUrlFull')
337                         ->with('http://test/install/testrewrite')
338                         ->andReturn($curlResultW);
339
340                 // Mocking that we can use CURL
341                 $this->setFunctions(['curl_init' => true]);
342
343                 $install = new Installer();
344
345                 $this->assertTrue($install->checkHtAccess('https://test'));
346         }
347
348         /**
349          * @small
350          * @runInSeparateProcess
351          * @preserveGlobalState disabled
352          */
353         public function testImagick()
354         {
355                 $this->markTestIncomplete('needs adapted class_exists() mock');
356
357                 $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
358
359                 $this->setClasses(['Imagick' => true]);
360
361                 $install = new Installer();
362
363                 // even there is no supported type, Imagick should return true (because it is not required)
364                 $this->assertTrue($install->checkImagick());
365
366                 $this->assertCheckExist(1,
367                         $this->l10nMock->t('ImageMagick supports GIF'),
368                         '',
369                         true,
370                         false,
371                         $install->getChecks());
372         }
373
374         /**
375          * @small
376          * @runInSeparateProcess
377          * @preserveGlobalState disabled
378          */
379         public function testImagickNotFound()
380         {
381                 $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
382
383                 $this->setClasses(['Imagick' => true]);
384
385                 $install = new Installer();
386
387                 // even there is no supported type, Imagick should return true (because it is not required)
388                 $this->assertTrue($install->checkImagick());
389                 $this->assertCheckExist(1,
390                         $this->l10nMock->t('ImageMagick supports GIF'),
391                         '',
392                         false,
393                         false,
394                         $install->getChecks());
395         }
396
397         public function testImagickNotInstalled()
398         {
399                 $this->setClasses(['Imagick' => false]);
400                 $this->mockL10nT('ImageMagick PHP extension is not installed');
401
402                 $install = new Installer();
403
404                 // even there is no supported type, Imagick should return true (because it is not required)
405                 $this->assertTrue($install->checkImagick());
406                 $this->assertCheckExist(0,
407                         'ImageMagick PHP extension is not installed',
408                         '',
409                         false,
410                         false,
411                         $install->getChecks());
412         }
413
414         /**
415          * Test the setup of the config cache for installation
416          */
417         public function testSetUpCache()
418         {
419                 $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
420
421                 $install = new Installer();
422                 $configCache = \Mockery::mock(ConfigCache::class);
423                 $configCache->shouldReceive('set')->with('config', 'php_path', \Mockery::any())->once();
424                 $configCache->shouldReceive('set')->with('system', 'basepath', '/test/')->once();
425
426                 $install->setUpCache($configCache, '/test/');
427         }
428 }
429
430 /**
431  * A workaround to replace the PHP native function_exists with a mocked function
432  *
433  * @param string $function_name the Name of the function
434  *
435  * @return bool true or false
436  */
437 function function_exists($function_name)
438 {
439         global $phpMock;
440         if (isset($phpMock['function_exists'])) {
441                 $result = call_user_func_array($phpMock['function_exists'], func_get_args());
442                 if ($result !== '__phpunit_continue__') {
443                         return $result;
444                 }
445         }
446         return call_user_func_array('\function_exists', func_get_args());
447 }
448
449 function class_exists($class_name)
450 {
451         global $phpMock;
452         if (isset($phpMock['class_exists'])) {
453                 $result = call_user_func_array($phpMock['class_exists'], func_get_args());
454                 if ($result !== '__phpunit_continue__') {
455                         return $result;
456                 }
457         }
458         return call_user_func_array('\class_exists', func_get_args());
459 }