Merge pull request #14004 from mfb/set-utf8
[civicrm-core.git] / tests / phpunit / E2E / Extern / RestTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
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 * Verify that the REST API bindings correctly parse and authenticate requests.
29 *
30 * @group e2e
31 */
32 class E2E_Extern_RestTest extends CiviEndToEndTestCase {
33 protected $url;
34 protected static $api_key;
35 protected $session_id;
36 protected $nocms_contact_id;
37 protected $old_api_keys;
38 protected $adminContactId;
39
40 /**
41 * @param $apiResult
42 * @param $cmpvar
43 * @param string $prefix
44 */
45 protected function assertAPIErrorCode($apiResult, $cmpvar, $prefix = '') {
46 if (!empty($prefix)) {
47 $prefix .= ': ';
48 }
49 $this->assertEquals($cmpvar, $apiResult['is_error'],
50 $prefix . (empty($apiResult['error_message']) ? '' : $apiResult['error_message']));
51 //$this->assertEquals($cmpvar, $apiResult['is_error'], $prefix . print_r($apiResult, TRUE));
52 }
53
54 protected function setUp() {
55 parent::setUp();
56
57 if (empty($GLOBALS['_CV']['CIVI_SITE_KEY'])) {
58 $this->markTestSkipped('Missing siteKey');
59 }
60
61 $this->old_api_keys = array();
62 }
63
64 protected function getRestUrl() {
65 return CRM_Core_Resources::singleton()
66 ->getUrl('civicrm', 'extern/rest.php');
67 }
68
69 protected function tearDown() {
70 if (!empty($this->old_api_keys)) {
71 foreach ($this->old_api_keys as $cid => $apiKey) {
72 civicrm_api3('Contact', 'create', array(
73 'id' => $cid,
74 'api_key' => $apiKey,
75 ));
76 }
77 }
78 parent::tearDown();
79 if (isset($this->nocms_contact_id)) {
80 $deleteParams = array(
81 "id" => $this->nocms_contact_id,
82 "skip_undelete" => 1,
83 );
84 $res = civicrm_api3("Contact", "delete", $deleteParams);
85 unset($this->nocms_contact_id);
86 }
87 }
88
89 /**
90 * Build a list of test cases. Each test case defines a set of REST query
91 * parameters and an expected outcome for the REST request (eg is_error=>1 or is_error=>0).
92 *
93 * @return array; each item is a list of parameters for testAPICalls
94 */
95 public function apiTestCases() {
96 $cases = array();
97
98 // entity,action: omit apiKey, valid entity+action
99 $cases[] = array(
100 // query
101 array(
102 "entity" => "Contact",
103 "action" => "get",
104 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
105 "json" => "1",
106 ),
107 // is_error
108 1,
109 );
110
111 // entity,action: valid apiKey, valid entity+action
112 $cases[] = array(
113 // query
114 array(
115 "entity" => "Contact",
116 "action" => "get",
117 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
118 "json" => "1",
119 "api_key" => self::getApiKey(),
120 ),
121 // is_error
122 0,
123 );
124
125 // entity,action: bad apiKey, valid entity+action
126 $cases[] = array(
127 // query
128 array(
129 "entity" => "Contact",
130 "action" => "get",
131 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
132 "json" => "1",
133 "api_key" => 'garbage_' . self::getApiKey(),
134 ),
135 // is_error
136 1,
137 );
138
139 // entity,action: valid apiKey, invalid entity+action
140 $cases[] = array(
141 // query
142 array(
143 "entity" => "Contactses",
144 "action" => "get",
145 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
146 "json" => "1",
147 "api_key" => self::getApiKey(),
148 ),
149 // is_error
150 1,
151 );
152
153 // q=civicrm/entity/action: omit apiKey, valid entity+action
154 $cases[] = array(
155 // query
156 array(
157 "q" => "civicrm/contact/get",
158 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
159 "json" => "1",
160 ),
161 // is_error
162 1,
163 );
164
165 // q=civicrm/entity/action: valid apiKey, valid entity+action
166 $cases[] = array(
167 // query
168 array(
169 "q" => "civicrm/contact/get",
170 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
171 "json" => "1",
172 "api_key" => self::getApiKey(),
173 ),
174 // is_error
175 0,
176 );
177
178 // q=civicrm/entity/action: invalid apiKey, valid entity+action
179 $cases[] = array(
180 // query
181 array(
182 "q" => "civicrm/contact/get",
183 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
184 "json" => "1",
185 "api_key" => 'garbage_' . self::getApiKey(),
186 ),
187 // is_error
188 1,
189 );
190
191 // q=civicrm/entity/action: valid apiKey, invalid entity+action
192 $cases[] = array(
193 // query
194 array(
195 "q" => "civicrm/contactses/get",
196 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
197 "json" => "1",
198 "api_key" => self::getApiKey(),
199 ),
200 // is_error
201 1,
202 );
203
204 // q=civicrm/entity/action: valid apiKey, invalid entity+action
205 // XXX Actually Ping is valid, no?
206 $cases[] = array(
207 // query
208 array(
209 "q" => "civicrm/ping",
210 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
211 "json" => "1",
212 "api_key" => self::getApiKey(),
213 ),
214 // is_error
215 0,
216 );
217
218 return $cases;
219 }
220
221 /**
222 * @dataProvider apiTestCases
223 * @param $query
224 * @param $is_error
225 */
226 public function testAPICalls($query, $is_error) {
227 $this->updateAdminApiKey();
228
229 $client = CRM_Utils_HttpClient::singleton();
230 list($status, $data) = $client->post($this->getRestUrl(), $query);
231 $this->assertEquals(CRM_Utils_HttpClient::STATUS_OK, $status);
232 $result = json_decode($data, TRUE);
233 if ($result === NULL) {
234 $msg = print_r(array(
235 'restUrl' => $this->getRestUrl(),
236 'query' => $query,
237 'response data' => $data,
238 ), TRUE);
239 $this->assertNotNull($result, $msg);
240 }
241 $this->assertAPIErrorCode($result, $is_error);
242 }
243
244 /**
245 * Submit a request with an API key that exists but does not correspond to.
246 * a real user. Submit in "?entity=X&action=X" notation
247 */
248 public function testNotCMSUser_entityAction() {
249 $client = CRM_Utils_HttpClient::singleton();
250
251 //Create contact with api_key
252 $test_key = "testing1234";
253 $contactParams = array(
254 "api_key" => $test_key,
255 "contact_type" => "Individual",
256 "first_name" => "RestTester1",
257 );
258 $contact = civicrm_api3("Contact", "create", $contactParams);
259 $this->nocms_contact_id = $contact["id"];
260
261 // The key associates with a real contact but not a real user
262 $params = array(
263 "entity" => "Contact",
264 "action" => "get",
265 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
266 "json" => "1",
267 "api_key" => $test_key,
268 );
269 list($status, $data) = $client->post($this->getRestUrl(), $params);
270 $this->assertEquals(CRM_Utils_HttpClient::STATUS_OK, $status);
271 $result = json_decode($data, TRUE);
272 $this->assertNotNull($result);
273 $this->assertAPIErrorCode($result, 1);
274 }
275
276 /**
277 * Submit a request with an API key that exists but does not correspond to.
278 * a real user. Submit in "?entity=X&action=X" notation
279 */
280 public function testGetCorrectUserBack() {
281 $this->updateAdminApiKey();
282 $client = CRM_Utils_HttpClient::singleton();
283
284 //Create contact with api_key
285 // The key associates with a real contact but not a real user
286 $params = array(
287 "entity" => "Contact",
288 "action" => "get",
289 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
290 "json" => "1",
291 "api_key" => self::getApiKey(),
292 "id" => "user_contact_id",
293 );
294 list($status, $data) = $client->post($this->getRestUrl(), $params);
295 $this->assertEquals(CRM_Utils_HttpClient::STATUS_OK, $status);
296 $result = json_decode($data, TRUE);
297 $this->assertNotNull($result);
298 $this->assertEquals($result['id'], $this->adminContactId);
299 }
300
301 /**
302 * Submit a request with an API key that exists but does not correspond to
303 * a real user. Submit in "?q=civicrm/$entity/$action" notation
304 */
305 public function testNotCMSUser_q() {
306 $client = CRM_Utils_HttpClient::singleton();
307
308 //Create contact with api_key
309 $test_key = "testing1234";
310 $contactParams = array(
311 "api_key" => $test_key,
312 "contact_type" => "Individual",
313 "first_name" => "RestTester1",
314 );
315 $contact = civicrm_api3("Contact", "create", $contactParams);
316 $this->nocms_contact_id = $contact["id"];
317
318 // The key associates with a real contact but not a real user
319 $params = array(
320 "q" => "civicrm/contact/get",
321 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
322 "json" => "1",
323 "api_key" => $test_key,
324 );
325 list($status, $data) = $client->post($this->getRestUrl(), $params);
326 $this->assertEquals(CRM_Utils_HttpClient::STATUS_OK, $status);
327 $result = json_decode($data, TRUE);
328 $this->assertNotNull($result);
329 $this->assertAPIErrorCode($result, 1);
330 }
331
332 protected function updateAdminApiKey() {
333 /** @var int $adminContactId */
334 $this->adminContactId = civicrm_api3('contact', 'getvalue', array(
335 'id' => '@user:' . $GLOBALS['_CV']['ADMIN_USER'],
336 'return' => 'id',
337 ));
338
339 $this->old_api_keys[$this->adminContactId] = CRM_Core_DAO::singleValueQuery('SELECT api_key FROM civicrm_contact WHERE id = %1', [
340 1 => [$this->adminContactId, 'Positive'],
341 ]);
342
343 //$this->old_admin_api_key = civicrm_api3('Contact', 'get', array(
344 // 'id' => $adminContactId,
345 // 'return' => 'api_key',
346 //));
347
348 civicrm_api3('Contact', 'create', array(
349 'id' => $this->adminContactId,
350 'api_key' => self::getApiKey(),
351 ));
352 }
353
354 protected static function getApiKey() {
355 if (empty(self::$api_key)) {
356 self::$api_key = mt_rand() . mt_rand();
357 }
358 return self::$api_key;
359 }
360
361 }