]> git.mxchange.org Git - friendica.git/blob - tests/src/Core/Console/AutomaticInstallationConsoleTest.php
Merge pull request #6923 from nupplaphil/issue/fix_tests
[friendica.git] / tests / src / Core / Console / AutomaticInstallationConsoleTest.php
1 <?php
2
3 namespace Friendica\Test\src\Core\Console;
4
5 use Friendica\Core\Config\Cache\ConfigCache;
6 use Friendica\Core\Console\AutomaticInstallation;
7 use Friendica\Core\Installer;
8 use Friendica\Core\Logger;
9 use Friendica\Test\Util\DBAMockTrait;
10 use Friendica\Test\Util\DBStructureMockTrait;
11 use Friendica\Test\Util\L10nMockTrait;
12 use Friendica\Test\Util\RendererMockTrait;
13 use Friendica\Util\Logger\VoidLogger;
14 use org\bovigo\vfs\vfsStream;
15 use org\bovigo\vfs\vfsStreamFile;
16
17 /**
18  * @runTestsInSeparateProcesses
19  * @preserveGlobalState disabled
20  * @requires PHP 7.0
21  */
22 class AutomaticInstallationConsoleTest extends ConsoleTest
23 {
24         use L10nMockTrait;
25         use DBAMockTrait;
26         use DBStructureMockTrait;
27         use RendererMockTrait;
28
29         /**
30          * @var vfsStreamFile Assert file without DB credentials
31          */
32         private $assertFile;
33         /**
34          * @var vfsStreamFile Assert file with DB credentials
35          */
36         private $assertFileDb;
37
38         /**
39          * @var ConfigCache The configuration cache to check after each test
40          */
41         private $configCache;
42
43         public function setUp()
44         {
45                 parent::setUp();
46
47                 if ($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.config.php')) {
48                         $this->root->getChild('config')
49                                 ->removeChild('local.config.php');
50                 }
51
52                 $this->mockL10nT();
53
54                 $this->configCache = new ConfigCache();
55                 $this->configCache->set('system', 'basepath', $this->root->url());
56                 $this->configCache->set('config', 'php_path', trim(shell_exec('which php')));
57                 $this->configCache->set('system', 'theme', 'smarty3');
58
59                 $this->mockApp($this->root, null, true);
60
61                 $this->configMock->shouldReceive('set')->andReturnUsing(function ($cat, $key, $value) {
62                         if ($key !== 'basepath') {
63                                 return $this->configCache->set($cat, $key, $value);
64                         } else {
65                                 return true;
66                         }
67                 });
68
69                 $this->configMock->shouldReceive('has')->andReturn(true);
70                 $this->configMock->shouldReceive('get')->andReturnUsing(function ($cat, $key) {
71                         return $this->configCache->get($cat, $key);
72                 });
73                 $this->configMock->shouldReceive('load')->andReturnUsing(function ($config, $overwrite = false) {
74                         return $this->configCache->load($config, $overwrite);
75                 });
76
77                 $this->mode->shouldReceive('isInstall')->andReturn(true);
78                 Logger::init(new VoidLogger());
79         }
80
81         /**
82          * Returns the dataset for each automatic installation test
83          *
84          * @return array the dataset
85          */
86         public function dataInstaller()
87         {
88                 return [
89                         'empty' => [
90                                 'data' => [
91                                         'database' => [
92                                                 'hostname'    => '',
93                                                 'username'    => '',
94                                                 'password'    => '',
95                                                 'database'    => '',
96                                                 'port'        => '',
97                                         ],
98                                         'config' => [
99                                                 'php_path'    => '',
100                                                 'admin_email' => '',
101                                         ],
102                                         'system' => [
103                                                 'urlpath'     => '',
104                                                 'default_timezone' => '',
105                                                 'language'    => '',
106                                         ],
107                                 ],
108                         ],
109                         'normal' => [
110                                 'data' => [
111                                         'database' => [
112                                                 'hostname'    => 'testhost',
113                                                 'port'        => 3306,
114                                                 'username'    => 'friendica',
115                                                 'password'    => 'a password',
116                                                 'database'    => 'database',
117                                         ],
118                                         'config' => [
119                                                 'php_path'    => '',
120                                                 'admin_email' => 'admin@philipp.info',
121                                         ],
122                                         'system' => [
123                                                 'urlpath'     => 'test/it',
124                                                 'default_timezone' => 'en',
125                                                 'language'    => 'Europe/Berlin',
126                                         ],
127                                 ],
128                         ],
129                         'special' => [
130                                 'data' => [
131                                         'database' => [
132                                                 'hostname'    => 'testhost.new.domain',
133                                                 'port'        => 3341,
134                                                 'username'    => 'fr"ยง%ica',
135                                                 'password'    => '$%\"gse',
136                                                 'database'    => 'db',
137                                         ],
138                                         'config' => [
139                                                 'php_path'    => '',
140                                                 'admin_email' => 'admin@philipp.info',
141                                         ],
142                                         'system' => [
143                                                 'urlpath'     => 'test/it',
144                                                 'default_timezone' => 'en',
145                                                 'language'    => 'Europe/Berlin',
146                                         ],
147                                 ],
148                         ],
149                 ];
150         }
151
152         private function assertFinished($txt, $withconfig = false, $copyfile = false)
153         {
154                 $cfg = '';
155
156                 if ($withconfig) {
157                         $cfg = <<<CFG
158
159
160 Creating config file...
161
162  Complete!
163 CFG;
164                 }
165
166                 if ($copyfile) {
167                         $cfg = <<<CFG
168
169
170 Copying config file...
171
172  Complete!
173 CFG;
174                 }
175
176                 $finished = <<<FIN
177 Initializing setup...
178
179  Complete!
180
181
182 Checking environment...
183
184  NOTICE: Not checking .htaccess/URL-Rewrite during CLI installation.
185
186  Complete!
187 {$cfg}
188
189
190 Checking database...
191
192  Complete!
193
194
195 Inserting data into database...
196
197  Complete!
198
199
200 Installing theme
201
202  Complete
203
204
205
206 Installation is finished
207
208
209 FIN;
210                 $this->assertEquals($finished, $txt);
211         }
212
213         private function assertStuckDB($txt)
214         {
215                 $finished = <<<FIN
216 Initializing setup...
217
218  Complete!
219
220
221 Checking environment...
222
223  NOTICE: Not checking .htaccess/URL-Rewrite during CLI installation.
224
225  Complete!
226
227
228 Creating config file...
229
230  Complete!
231
232
233 Checking database...
234
235 [Error] --------
236 Could not connect to database.: 
237
238
239 FIN;
240
241                 $this->assertEquals($finished, $txt);
242         }
243
244         /**
245          * Asserts one config entry
246          *
247          * @param string     $cat           The category to test
248          * @param string     $key           The key to test
249          * @param null|array $assertion     The asserted value (null = empty, or array/string)
250          * @param string     $default_value The default value
251          */
252         public function assertConfigEntry($cat, $key, $assertion = null, $default_value = null)
253         {
254                 if (!empty($assertion[$cat][$key])) {
255                         $this->assertEquals($assertion[$cat][$key], $this->configCache->get($cat, $key));
256                 } elseif (!empty($assertion) && !is_array($assertion)) {
257                         $this->assertEquals($assertion, $this->configCache->get($cat, $key));
258                 } elseif (!empty($default_value)) {
259                         $this->assertEquals($default_value, $this->configCache->get($cat, $key));
260                 } else {
261                         $this->assertEmpty($this->configCache->get($cat, $key), $this->configCache->get($cat, $key));
262                 }
263         }
264
265         /**
266          * Asserts all config entries
267          *
268          * @param null|array $assertion    The optional assertion array
269          * @param boolean    $saveDb       True, if the db credentials should get saved to the file
270          * @param boolean    $default      True, if we use the default values
271          * @param boolean    $defaultDb    True, if we use the default value for the DB
272          */
273         public function assertConfig($assertion = null, $saveDb = false, $default = true, $defaultDb = true)
274         {
275                 if (!empty($assertion['database']['hostname'])) {
276                         $assertion['database']['hostname'] .= (!empty($assertion['database']['port']) ? ':' . $assertion['database']['port'] : '');
277                 }
278
279                 $this->assertConfigEntry('database', 'hostname', ($saveDb) ? $assertion : null, (!$saveDb || $defaultDb) ? Installer::DEFAULT_HOST : null);
280                 $this->assertConfigEntry('database', 'username', ($saveDb) ? $assertion : null);
281                 $this->assertConfigEntry('database', 'password', ($saveDb) ? $assertion : null);
282                 $this->assertConfigEntry('database', 'database', ($saveDb) ? $assertion : null);
283
284                 $this->assertConfigEntry('config', 'admin_email', $assertion);
285                 $this->assertConfigEntry('config', 'php_path', trim(shell_exec('which php')));
286
287                 $this->assertConfigEntry('system', 'default_timezone', $assertion, ($default) ? Installer::DEFAULT_TZ : null);
288                 $this->assertConfigEntry('system', 'language', $assertion, ($default) ? Installer::DEFAULT_LANG : null);
289         }
290
291         /**
292          * Test the automatic installation without any parameter/setting
293          */
294         public function testEmpty()
295         {
296                 $this->app->shouldReceive('getURLPath')->andReturn('')->atLeast()->once();
297
298                 $this->mockConnect(true, 1);
299                 $this->mockConnected(true, 1);
300                 $this->mockExistsTable('user', false, 1);
301                 $this->mockUpdate([$this->root->url(), false, true, true], null, 1);
302
303                 $this->mockGetMarkupTemplate('local.config.tpl', 'testTemplate', 1);
304                 $this->mockReplaceMacros('testTemplate', \Mockery::any(), '', 1);
305
306                 $console = new AutomaticInstallation($this->consoleArgv);
307
308                 $txt = $this->dumpExecute($console);
309
310                 $this->assertFinished($txt, true, false);
311                 $this->assertTrue($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.config.php'));
312
313                 $this->assertConfig();
314         }
315
316         /**
317          * Test the automatic installation with a prepared config file
318          * @dataProvider dataInstaller
319          */
320         public function testWithConfig(array $data)
321         {
322                 $this->mockConnect(true, 1);
323                 $this->mockConnected(true, 1);
324                 $this->mockExistsTable('user', false, 1);
325                 $this->mockUpdate([$this->root->url(), false, true, true], null, 1);
326
327                 $conf = function ($cat, $key) use ($data) {
328                         if ($cat == 'database' && $key == 'hostname' && !empty($data['database']['port'])) {
329                                 return $data[$cat][$key] . ':' . $data['database']['port'];
330                         }
331                         return $data[$cat][$key];
332                 };
333
334                 $config = <<<CONF
335 <?php
336
337 // Local configuration
338
339 // If you're unsure about what any of the config keys below do, please check the config/defaults.config.php for detailed
340 // documentation of their data type and behavior.
341
342 return [
343         'database' => [
344                 'hostname' => '{$conf('database', 'hostname')}',
345                 'username' => '{$conf('database', 'username')}',
346                 'password' => '{$conf('database', 'password')}',
347                 'database' => '{$conf('database', 'database')}',
348                 'charset' => 'utf8mb4',
349         ],
350
351         // ****************************************************************
352         // The configuration below will be overruled by the admin panel.
353         // Changes made below will only have an effect if the database does
354         // not contain any configuration for the friendica system.
355         // ****************************************************************
356
357         'config' => [
358                 'admin_email' => '{$conf('config', 'admin_email')}',
359                 'sitename' => 'Friendica Social Network',
360                 'register_policy' => \Friendica\Module\Register::OPEN,
361                 'register_text' => '',
362         ],
363         'system' => [
364                 'urlpath' => '{$conf('system', 'urlpath')}',
365                 'default_timezone' => '{$conf('system', 'default_timezone')}',
366                 'language' => '{$conf('system', 'language')}',
367         ],
368 ];
369 CONF;
370
371                 vfsStream::newFile('prepared.config.php')
372                         ->at($this->root)
373                         ->setContent($config);
374
375                 $console = new AutomaticInstallation($this->consoleArgv);
376                 $console->setOption('f', 'prepared.config.php');
377
378                 $txt = $this->dumpExecute($console);
379
380                 $this->assertFinished($txt, false, true);
381
382                 $this->assertTrue($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.config.php'));
383                 $this->assertEquals($config, file_get_contents($this->root->getChild('config' . DIRECTORY_SEPARATOR . 'local.config.php')->url()));
384
385                 $this->assertConfig($data, true, false, false);
386         }
387
388         /**
389          * Test the automatic installation with environment variables
390          * Includes saving the DB credentials to the file
391          * @dataProvider dataInstaller
392          */
393         public function testWithEnvironmentAndSave(array $data)
394         {
395                 $this->app->shouldReceive('getURLPath')->andReturn('')->atLeast()->once();
396
397                 $this->mockConnect(true, 1);
398                 $this->mockConnected(true, 1);
399                 $this->mockExistsTable('user', false, 1);
400                 $this->mockUpdate([$this->root->url(), false, true, true], null, 1);
401
402                 $this->mockGetMarkupTemplate('local.config.tpl', 'testTemplate', 1);
403                 $this->mockReplaceMacros('testTemplate', \Mockery::any(), '', 1);
404
405                 $this->assertTrue(putenv('MYSQL_HOST='     . $data['database']['hostname']));
406                 $this->assertTrue(putenv('MYSQL_PORT='     . $data['database']['port']));
407                 $this->assertTrue(putenv('MYSQL_DATABASE=' . $data['database']['database']));
408                 $this->assertTrue(putenv('MYSQL_USERNAME=' . $data['database']['username']));
409                 $this->assertTrue(putenv('MYSQL_PASSWORD=' . $data['database']['password']));
410
411                 $this->assertTrue(putenv('FRIENDICA_URL_PATH='   . $data['system']['urlpath']));
412                 $this->assertTrue(putenv('FRIENDICA_PHP_PATH='   . $data['config']['php_path']));
413                 $this->assertTrue(putenv('FRIENDICA_ADMIN_MAIL=' . $data['config']['admin_email']));
414                 $this->assertTrue(putenv('FRIENDICA_TZ='         . $data['system']['default_timezone']));
415                 $this->assertTrue(putenv('FRIENDICA_LANG='       . $data['system']['language']));
416
417                 $console = new AutomaticInstallation($this->consoleArgv);
418                 $console->setOption('savedb', true);
419
420                 $txt = $this->dumpExecute($console);
421
422                 $this->assertFinished($txt, true);
423                 $this->assertConfig($data, true, true, false);
424         }
425
426         /**
427          * Test the automatic installation with environment variables
428          * Don't save the db credentials to the file
429          * @dataProvider dataInstaller
430          */
431         public function testWithEnvironmentWithoutSave(array $data)
432         {
433                 $this->app->shouldReceive('getURLPath')->andReturn('')->atLeast()->once();
434
435                 $this->mockConnect(true, 1);
436                 $this->mockConnected(true, 1);
437                 $this->mockExistsTable('user', false, 1);
438                 $this->mockUpdate([$this->root->url(), false, true, true], null, 1);
439
440                 $this->mockGetMarkupTemplate('local.config.tpl', 'testTemplate', 1);
441                 $this->mockReplaceMacros('testTemplate', \Mockery::any(), '', 1);
442
443                 $this->assertTrue(putenv('MYSQL_HOST=' . $data['database']['hostname']));
444                 $this->assertTrue(putenv('MYSQL_PORT=' . $data['database']['port']));
445                 $this->assertTrue(putenv('MYSQL_DATABASE=' . $data['database']['database']));
446                 $this->assertTrue(putenv('MYSQL_USERNAME=' . $data['database']['username']));
447                 $this->assertTrue(putenv('MYSQL_PASSWORD=' . $data['database']['password']));
448
449                 $this->assertTrue(putenv('FRIENDICA_URL_PATH=' . $data['system']['urlpath']));
450                 $this->assertTrue(putenv('FRIENDICA_PHP_PATH=' . $data['config']['php_path']));
451                 $this->assertTrue(putenv('FRIENDICA_ADMIN_MAIL=' . $data['config']['admin_email']));
452                 $this->assertTrue(putenv('FRIENDICA_TZ=' . $data['system']['default_timezone']));
453                 $this->assertTrue(putenv('FRIENDICA_LANG=' . $data['system']['language']));
454
455                 $console = new AutomaticInstallation($this->consoleArgv);
456
457                 $txt = $this->dumpExecute($console);
458
459                 $this->assertFinished($txt, true);
460                 $this->assertConfig($data, false, true);
461         }
462
463         /**
464          * Test the automatic installation with arguments
465          * @dataProvider dataInstaller
466          */
467         public function testWithArguments(array $data)
468         {
469                 $this->app->shouldReceive('getURLPath')->andReturn('')->atLeast()->once();
470
471                 $this->mockConnect(true, 1);
472                 $this->mockConnected(true, 1);
473                 $this->mockExistsTable('user', false, 1);
474                 $this->mockUpdate([$this->root->url(), false, true, true], null, 1);
475
476                 $this->mockGetMarkupTemplate('local.config.tpl', 'testTemplate', 1);
477                 $this->mockReplaceMacros('testTemplate', \Mockery::any(), '', 1);
478
479                 $console = new AutomaticInstallation($this->consoleArgv);
480
481                 $option = function($var, $cat, $key) use ($data, $console) {
482                         if (!empty($data[$cat][$key])) {
483                                 $console->setOption($var, $data[$cat][$key]);
484                         }
485                 };
486                 $option('dbhost'   , 'database', 'hostname');
487                 $option('dbport'   , 'database', 'port');
488                 $option('dbuser'   , 'database', 'username');
489                 $option('dbpass'   , 'database', 'password');
490                 $option('dbdata'   , 'database', 'database');
491                 $option('urlpath'  , 'system'  , 'urlpath');
492                 $option('phppath'  , 'config'  , 'php_path');
493                 $option('admin'    , 'config'  , 'admin_email');
494                 $option('tz'       , 'system'  , 'default_timezone');
495                 $option('lang'     , 'system'  , 'language');
496
497                 $txt = $this->dumpExecute($console);
498
499                 $this->assertFinished($txt, true);
500                 $this->assertConfig($data, true, true, true);
501         }
502
503         /**
504          * Test the automatic installation with a wrong database connection
505          */
506         public function testNoDatabaseConnection()
507         {
508                 $this->app->shouldReceive('getURLPath')->andReturn('')->atLeast()->once();
509                 $this->mockConnect(false, 1);
510
511                 $this->mockGetMarkupTemplate('local.config.tpl', 'testTemplate', 1);
512                 $this->mockReplaceMacros('testTemplate', \Mockery::any(), '', 1);
513
514                 $console = new AutomaticInstallation($this->consoleArgv);
515
516                 $txt = $this->dumpExecute($console);
517
518                 $this->assertStuckDB($txt);
519                 $this->assertTrue($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.config.php'));
520
521                 $this->assertConfig(null, false, true, false);
522         }
523
524         public function testGetHelp()
525         {
526                 // Usable to purposely fail if new commands are added without taking tests into account
527                 $theHelp = <<<HELP
528 Installation - Install Friendica automatically
529 Synopsis
530         bin/console autoinstall [-h|--help|-?] [-v] [-a] [-f]
531
532 Description
533     Installs Friendica with data based on the local.config.php file or environment variables
534
535 Notes
536     Not checking .htaccess/URL-Rewrite during CLI installation.
537
538 Options
539     -h|--help|-?            Show help information
540     -v                      Show more debug information.
541     -a                      All setup checks are required (except .htaccess)
542     -f|--file <config>      prepared config file (e.g. "config/local.config.php" itself) which will override every other config option - except the environment variables)
543     -s|--savedb             Save the DB credentials to the file (if environment variables is used)
544     -H|--dbhost <host>      The host of the mysql/mariadb database (env MYSQL_HOST)
545     -p|--dbport <port>      The port of the mysql/mariadb database (env MYSQL_PORT)
546     -d|--dbdata <database>  The name of the mysql/mariadb database (env MYSQL_DATABASE)
547     -U|--dbuser <username>  The username of the mysql/mariadb database login (env MYSQL_USER or MYSQL_USERNAME)
548     -P|--dbpass <password>  The password of the mysql/mariadb database login (env MYSQL_PASSWORD)
549     -u|--urlpath <url_path> The URL path of Friendica - f.e. '/friendica' (env FRIENDICA_URL_PATH) 
550     -b|--phppath <php_path> The path of the PHP binary (env FRIENDICA_PHP_PATH) 
551     -A|--admin <mail>       The admin email address of Friendica (env FRIENDICA_ADMIN_MAIL)
552     -T|--tz <timezone>      The timezone of Friendica (env FRIENDICA_TZ)
553     -L|--lang <language>    The language of Friendica (env FRIENDICA_LANG)
554  
555 Environment variables
556    MYSQL_HOST                  The host of the mysql/mariadb database (mandatory if mysql and environment is used)
557    MYSQL_PORT                  The port of the mysql/mariadb database
558    MYSQL_USERNAME|MYSQL_USER   The username of the mysql/mariadb database login (MYSQL_USERNAME is for mysql, MYSQL_USER for mariadb)
559    MYSQL_PASSWORD              The password of the mysql/mariadb database login
560    MYSQL_DATABASE              The name of the mysql/mariadb database
561    FRIENDICA_URL_PATH          The URL path of Friendica (f.e. '/friendica')
562    FRIENDICA_PHP_PATH          The path of the PHP binary
563    FRIENDICA_ADMIN_MAIL        The admin email address of Friendica (this email will be used for admin access)
564    FRIENDICA_TZ                The timezone of Friendica
565    FRIENDICA_LANG              The langauge of Friendica
566    
567 Examples
568         bin/console autoinstall -f 'input.config.php
569                 Installs Friendica with the prepared 'input.config.php' file
570
571         bin/console autoinstall --savedb
572                 Installs Friendica with environment variables and saves them to the 'config/local.config.php' file
573
574         bin/console autoinstall -h localhost -p 3365 -U user -P passwort1234 -d friendica
575                 Installs Friendica with a local mysql database with credentials
576
577 HELP;
578
579                 $console = new AutomaticInstallation($this->consoleArgv);
580                 $console->setOption('help', true);
581
582                 $txt = $this->dumpExecute($console);
583
584                 $this->assertEquals($theHelp, $txt);
585         }
586 }