Merge pull request #17448 from mattwire/api4membershiptype
[civicrm-core.git] / tests / phpunit / E2E / Extern / CliRunnerTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2020 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License along with this program; if not, contact CiviCRM LLC |
21 | at info[AT]civicrm[DOT]org. If you have questions about the |
22 | GNU Affero General Public License or the licensing of CiviCRM, |
23 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
24 +--------------------------------------------------------------------+
25 */
26
27 /**
28 * Check that various CLI runners are able to bootstrap an environment with
29 * reasonable paths.
30 *
31 * This test assumes that you have built with "civibuild" (or configured cv.json)
32 * to provide canonical/expected values.
33 *
34 * It then executes the any supported CLI tools (cv, drush, wp) and checks if
35 * their output matches the expected value.
36 *
37 * @group e2e
38 */
39 class E2E_Extern_CliRunnerTest extends CiviEndToEndTestCase {
40
41 protected function setUp() {
42 parent::setUp();
43
44 foreach (['CIVI_CORE', 'CMS_ROOT', 'CMS_URL'] as $var) {
45 if (empty($GLOBALS['_CV'][$var])) {
46 $this->markTestSkipped("Test environment does provide the civibuild/cv variable ($var)");
47 }
48 }
49 }
50
51 protected function tearDown() {
52 parent::tearDown();
53 }
54
55 /**
56 * @return array
57 * Each case gives a name (eg "cv") and template for executing the command
58 * (eg "cv ev @PHP").
59 */
60 public function getRunners() {
61 $cliRunners = [];
62
63 if (CIVICRM_UF === 'WordPress') {
64 $cliRunners['wp'] = ['wp', 'wp eval \'civicrm_initialize();\'@PHP'];
65 }
66 if (CIVICRM_UF === 'Drupal' || CIVICRM_UF === 'Backdrop') {
67 $cliRunners['drush'] = ['drush', 'drush ev \'civicrm_initialize();\'@PHP'];
68 }
69 // TODO: Drupal8 w/drush (doesn't use civicrm_initialize?)
70
71 $cliRunners['cv'] = ['cv', 'cv ev @PHP'];
72
73 return $cliRunners;
74 }
75
76 public function getRunnersAndPaths() {
77 $exs = [];
78 foreach ($this->getRunners() as $runner) {
79 $exs[] = array_merge($runner, ['[civicrm.root]/css/civicrm.css']);
80 $exs[] = array_merge($runner, ['[civicrm.packages]/jquery/css/images/arrow.png']);
81 }
82 return $exs;
83 }
84
85 /**
86 * @param string $name
87 * The name of the command we're testing with.
88 * Ex: 'cv'
89 * @param string $r
90 * Ex: 'cv ev @PHP'
91 * @dataProvider getRunners
92 */
93 public function testBasicPathUrl($name, $r) {
94 $this->assertNotEmpty($this->findCommand($name), 'The command "$name" does not appear in the PATH.');
95
96 $cv = $GLOBALS['_CV'];
97 $this->assertEquals($cv['CIVI_CORE'], $this->callRunnerJson($r, '$GLOBALS[\'civicrm_root\']'));
98 $this->assertEquals($cv['CMS_URL'] . 'foo', $this->callRunnerJson($r, 'Civi::paths()->getUrl(\'[cms.root]/foo\')'));
99 $this->assertEquals($cv['CMS_ROOT'] . 'foo', $this->callRunnerJson($r, 'Civi::paths()->getPath(\'[cms.root]/foo\')'));
100 $this->assertEquals($cv['CIVI_CORE'] . 'css/civicrm.css', $this->callRunnerJson($r, 'Civi::paths()->getPath(\'[civicrm.root]/css/civicrm.css\')'));
101
102 $ufrUrl = $this->callRunnerJson($r, 'CRM_Core_Config::singleton()->userFrameworkResourceURL');
103 $crmUrl = $this->callRunnerJson($r, 'Civi::paths()->getUrl("[civicrm.root]/.")');
104 $this->assertEquals(rtrim($crmUrl, '/'), rtrim($ufrUrl, '/'));
105 }
106
107 /**
108 * For some URLs, we don't have a good environment variable for predicting the URL.
109 * Instead, we'll just see if the generated URLs match the generated paths.
110 *
111 * @param string $name
112 * The name of the command we're testing with.
113 * Ex: 'cv'
114 * @param string $r
115 * Ex: 'cv ev @PHP'
116 * @param string $fileExpr
117 * Ex: '[civicrm.root]/LICENSE'
118 * @dataProvider getRunnersAndPaths
119 */
120 public function testPathUrlMatch($name, $r, $fileExpr) {
121 $this->assertNotEmpty($this->findCommand($name), 'The command "$name" does not appear in the PATH.');
122 $localPath = $this->callRunnerJson($r, "Civi::paths()->getPath('$fileExpr')");
123 $remoteUrl = $this->callRunnerJson($r, "Civi::paths()->getUrl('$fileExpr')");
124 $this->assertFileExists($localPath);
125 $localContent = file_get_contents($localPath);
126 $this->assertNotEmpty($localContent);
127 $this->assertEquals($localContent, file_get_contents($remoteUrl),
128 "civicrm.css should yield same content via local path ($localPath) or HTTP URL ($remoteUrl)"
129 );
130 }
131
132 /**
133 * @param string $runner
134 * Ex: 'cv ev @PHP'
135 * @param string $phpExpr
136 * PHP expression to evaluate and return. (Encoded+decoded as JSON)
137 * @return mixed
138 * The result of running $phpExpr through the given $runner.
139 */
140 protected function callRunnerJson($runner, $phpExpr) {
141 $json = $this->callRunnerOk($runner, "echo json_encode($phpExpr);");
142 return json_decode($json);
143 }
144
145 /**
146 * @param string $runner
147 * Ex: 'cv ev @PHP'
148 * @param string $phpStmt
149 * PHP code to execute
150 * @return string
151 * The console output of running $phpStmt through the given $runner.
152 */
153 protected function callRunnerOk($runner, $phpStmt) {
154 $cmd = strtr($runner, ['@PHP' => escapeshellarg($phpStmt)]);
155 exec($cmd, $output, $val);
156 $this->assertEquals(0, $val, "Command returned error ($cmd) ($val)");
157 return implode("", $output);
158 }
159
160 protected function findCommand($name) {
161 $paths = explode(PATH_SEPARATOR, getenv('PATH'));
162 foreach ($paths as $path) {
163 if (file_exists("$path/$name")) {
164 return "$path/$name";
165 }
166 }
167 return NULL;
168 }
169
170 }