3 // this is in the same namespace as Install for mocking 'function_exists'
4 namespace Friendica\Core;
7 use Friendica\BaseObject;
8 use Friendica\Core\Config\Cache\ConfigCache;
9 use Friendica\Network\CurlResult;
10 use Friendica\Object\Image;
11 use Friendica\Test\MockedTest;
12 use Friendica\Test\Util\VFSTrait;
13 use Friendica\Util\Network;
14 use Mockery\MockInterface;
16 class InstallerTest extends MockedTest
21 * @var \Friendica\Core\L10n\L10n|MockInterface
25 public function setUp()
31 $this->l10nMock = \Mockery::mock(\Friendica\Core\L10n\L10n::class);
33 /** @var Dice|MockInterface $dice */
34 $dice = \Mockery::mock(Dice::class)->makePartial();
35 $dice = $dice->addRules(include __DIR__ . '/../../../static/dependencies.config.php');
37 $dice->shouldReceive('create')
38 ->with(\Friendica\Core\L10n\L10n::class)
39 ->andReturn($this->l10nMock);
41 BaseObject::setDependencyInjection($dice);
44 private function mockL10nT(string $text, $times = null)
46 $this->l10nMock->shouldReceive('t')->with($text)->andReturn($text)->times($times);
50 * Mocking the L10n::t() calls for the function checks
52 private function mockFunctionL10TCalls()
54 $this->mockL10nT('Apache mod_rewrite module', 1);
55 $this->mockL10nT('PDO or MySQLi PHP module', 1);
56 $this->mockL10nT('libCurl PHP module', 1);
57 $this->mockL10nT('Error: libCURL PHP module required but not installed.', 1);
58 $this->mockL10nT('XML PHP module', 1);
59 $this->mockL10nT('GD graphics PHP module', 1);
60 $this->mockL10nT('Error: GD graphics PHP module with JPEG support required but not installed.', 1);
61 $this->mockL10nT('OpenSSL PHP module', 1);
62 $this->mockL10nT('Error: openssl PHP module required but not installed.', 1);
63 $this->mockL10nT('mb_string PHP module', 1);
64 $this->mockL10nT('Error: mb_string PHP module required but not installed.', 1);
65 $this->mockL10nT('iconv PHP module', 1);
66 $this->mockL10nT('Error: iconv PHP module required but not installed.', 1);
67 $this->mockL10nT('POSIX PHP module', 1);
68 $this->mockL10nT('Error: POSIX PHP module required but not installed.', 1);
69 $this->mockL10nT('JSON PHP module', 1);
70 $this->mockL10nT('Error: JSON PHP module required but not installed.', 1);
71 $this->mockL10nT('File Information PHP module', 1);
72 $this->mockL10nT('Error: File Information PHP module required but not installed.', 1);
75 private function assertCheckExist($position, $title, $help, $status, $required, $assertionArray)
77 $this->assertArraySubset([$position => [
80 'required' => $required,
87 * Replaces function_exists results with given mocks
89 * @param array $functions a list from function names and their result
91 private function setFunctions($functions)
94 $phpMock['function_exists'] = function($function) use ($functions) {
95 foreach ($functions as $name => $value) {
96 if ($function == $name) {
100 return '__phpunit_continue__';
105 * Replaces class_exist results with given mocks
107 * @param array $classes a list from class names and their results
109 private function setClasses($classes)
112 $phpMock['class_exists'] = function($class) use ($classes) {
113 foreach ($classes as $name => $value) {
114 if ($class == $name) {
118 return '__phpunit_continue__';
125 public function testCheckKeys()
127 $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
129 $this->setFunctions(['openssl_pkey_new' => false]);
130 $install = new Installer();
131 $this->assertFalse($install->checkKeys());
133 $this->setFunctions(['openssl_pkey_new' => true]);
134 $install = new Installer();
135 $this->assertTrue($install->checkKeys());
141 public function testCheckFunctions()
143 $this->mockFunctionL10TCalls();
144 $this->setFunctions(['curl_init' => false, 'imagecreatefromjpeg' => true]);
145 $install = new Installer();
146 $this->assertFalse($install->checkFunctions());
147 $this->assertCheckExist(3,
148 'libCurl PHP module',
149 'Error: libCURL PHP module required but not installed.',
152 $install->getChecks());
154 $this->mockFunctionL10TCalls();
155 $this->setFunctions(['imagecreatefromjpeg' => false]);
156 $install = new Installer();
157 $this->assertFalse($install->checkFunctions());
158 $this->assertCheckExist(4,
159 'GD graphics PHP module',
160 'Error: GD graphics PHP module with JPEG support required but not installed.',
163 $install->getChecks());
165 $this->mockFunctionL10TCalls();
166 $this->setFunctions(['openssl_public_encrypt' => false]);
167 $install = new Installer();
168 $this->assertFalse($install->checkFunctions());
169 $this->assertCheckExist(5,
170 'OpenSSL PHP module',
171 'Error: openssl PHP module required but not installed.',
174 $install->getChecks());
176 $this->mockFunctionL10TCalls();
177 $this->setFunctions(['mb_strlen' => false]);
178 $install = new Installer();
179 $this->assertFalse($install->checkFunctions());
180 $this->assertCheckExist(6,
181 'mb_string PHP module',
182 'Error: mb_string PHP module required but not installed.',
185 $install->getChecks());
187 $this->mockFunctionL10TCalls();
188 $this->setFunctions(['iconv_strlen' => false]);
189 $install = new Installer();
190 $this->assertFalse($install->checkFunctions());
191 $this->assertCheckExist(7,
193 'Error: iconv PHP module required but not installed.',
196 $install->getChecks());
198 $this->mockFunctionL10TCalls();
199 $this->setFunctions(['posix_kill' => false]);
200 $install = new Installer();
201 $this->assertFalse($install->checkFunctions());
202 $this->assertCheckExist(8,
204 'Error: POSIX PHP module required but not installed.',
207 $install->getChecks());
209 $this->mockFunctionL10TCalls();
210 $this->setFunctions(['json_encode' => false]);
211 $install = new Installer();
212 $this->assertFalse($install->checkFunctions());
213 $this->assertCheckExist(9,
215 'Error: JSON PHP module required but not installed.',
218 $install->getChecks());
220 $this->mockFunctionL10TCalls();
221 $this->setFunctions(['finfo_open' => false]);
222 $install = new Installer();
223 $this->assertFalse($install->checkFunctions());
224 $this->assertCheckExist(10,
225 'File Information PHP module',
226 'Error: File Information PHP module required but not installed.',
229 $install->getChecks());
231 $this->mockFunctionL10TCalls();
232 $this->setFunctions([
234 'imagecreatefromjpeg' => true,
235 'openssl_public_encrypt' => true,
237 'iconv_strlen' => true,
238 'posix_kill' => true,
239 'json_encode' => true,
240 'finfo_open' => true,
242 $install = new Installer();
243 $this->assertTrue($install->checkFunctions());
249 public function testCheckLocalIni()
251 $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
253 $this->assertTrue($this->root->hasChild('config/local.config.php'));
255 $install = new Installer();
256 $this->assertTrue($install->checkLocalIni());
258 $this->delConfigFile('local.config.php');
260 $this->assertFalse($this->root->hasChild('config/local.config.php'));
262 $install = new Installer();
263 $this->assertTrue($install->checkLocalIni());
268 * @runInSeparateProcess
269 * @preserveGlobalState disabled
271 public function testCheckHtAccessFail()
273 $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
275 // Mocking the CURL Response
276 $curlResult = \Mockery::mock(CurlResult::class);
278 ->shouldReceive('getReturnCode')
281 ->shouldReceive('getRedirectUrl')
284 ->shouldReceive('getError')
285 ->andReturn('test Error');
287 // Mocking the CURL Request
288 $networkMock = \Mockery::mock('alias:' . Network::class);
290 ->shouldReceive('fetchUrlFull')
291 ->with('https://test/install/testrewrite')
292 ->andReturn($curlResult);
294 ->shouldReceive('fetchUrlFull')
295 ->with('http://test/install/testrewrite')
296 ->andReturn($curlResult);
298 // Mocking that we can use CURL
299 $this->setFunctions(['curl_init' => true]);
301 $install = new Installer();
303 $this->assertFalse($install->checkHtAccess('https://test'));
304 $this->assertSame('test Error', $install->getChecks()[0]['error_msg']['msg']);
309 * @runInSeparateProcess
310 * @preserveGlobalState disabled
312 public function testCheckHtAccessWork()
314 $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
316 // Mocking the failed CURL Response
317 $curlResultF = \Mockery::mock(CurlResult::class);
319 ->shouldReceive('getReturnCode')
322 // Mocking the working CURL Response
323 $curlResultW = \Mockery::mock(CurlResult::class);
325 ->shouldReceive('getReturnCode')
328 // Mocking the CURL Request
329 $networkMock = \Mockery::mock('alias:' . Network::class);
331 ->shouldReceive('fetchUrlFull')
332 ->with('https://test/install/testrewrite')
333 ->andReturn($curlResultF);
335 ->shouldReceive('fetchUrlFull')
336 ->with('http://test/install/testrewrite')
337 ->andReturn($curlResultW);
339 // Mocking that we can use CURL
340 $this->setFunctions(['curl_init' => true]);
342 // needed because of "normalise_link"
343 require_once __DIR__ . '/../../../include/text.php';
345 $install = new Installer();
347 $this->assertTrue($install->checkHtAccess('https://test'));
352 * @runInSeparateProcess
353 * @preserveGlobalState disabled
355 public function testImagick()
357 $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
359 $imageMock = \Mockery::mock('alias:'. Image::class);
361 ->shouldReceive('supportedTypes')
362 ->andReturn(['image/gif' => 'gif']);
364 $this->setClasses(['Imagick' => true]);
366 $install = new Installer();
368 // even there is no supported type, Imagick should return true (because it is not required)
369 $this->assertTrue($install->checkImagick());
371 $this->assertCheckExist(1,
372 L10n::t('ImageMagick supports GIF'),
376 $install->getChecks());
381 * @runInSeparateProcess
382 * @preserveGlobalState disabled
384 public function testImagickNotFound()
386 $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
388 $imageMock = \Mockery::mock('alias:' . Image::class);
390 ->shouldReceive('supportedTypes')
393 $this->setClasses(['Imagick' => true]);
395 $install = new Installer();
397 // even there is no supported type, Imagick should return true (because it is not required)
398 $this->assertTrue($install->checkImagick());
399 $this->assertCheckExist(1,
400 L10n::t('ImageMagick supports GIF'),
404 $install->getChecks());
407 public function testImagickNotInstalled()
409 $this->setClasses(['Imagick' => false]);
410 $this->mockL10nT('ImageMagick PHP extension is not installed');
412 $install = new Installer();
414 // even there is no supported type, Imagick should return true (because it is not required)
415 $this->assertTrue($install->checkImagick());
416 $this->assertCheckExist(0,
417 'ImageMagick PHP extension is not installed',
421 $install->getChecks());
425 * Test the setup of the config cache for installation
427 public function testSetUpCache()
429 $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
431 $install = new Installer();
432 $configCache = \Mockery::mock(ConfigCache::class);
433 $configCache->shouldReceive('set')->with('config', 'php_path', \Mockery::any())->once();
434 $configCache->shouldReceive('set')->with('system', 'basepath', '/test/')->once();
436 $install->setUpCache($configCache, '/test/');
441 * A workaround to replace the PHP native function_exists with a mocked function
443 * @param string $function_name the Name of the function
445 * @return bool true or false
447 function function_exists($function_name)
450 if (isset($phpMock['function_exists'])) {
451 $result = call_user_func_array($phpMock['function_exists'], func_get_args());
452 if ($result !== '__phpunit_continue__') {
456 return call_user_func_array('\function_exists', func_get_args());
459 function class_exists($class_name)
462 if (isset($phpMock['class_exists'])) {
463 $result = call_user_func_array($phpMock['class_exists'], func_get_args());
464 if ($result !== '__phpunit_continue__') {
468 return call_user_func_array('\class_exists', func_get_args());