Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

459 lines
12 KiB

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