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