PageRenderTime 34ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php

https://bitbucket.org/aswinvk28/smartpan-stock-drupal
PHP | 341 lines | 181 code | 28 blank | 132 comment | 14 complexity | 482e8a500c9624f4f20fd24099fb409b MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * @file
  4. * Definition of Drupal\rest\test\RESTTestBase.
  5. */
  6. namespace Drupal\rest\Tests;
  7. use Drupal\Core\Session\AccountInterface;
  8. use Drupal\simpletest\WebTestBase;
  9. /**
  10. * Test helper class that provides a REST client method to send HTTP requests.
  11. */
  12. abstract class RESTTestBase extends WebTestBase {
  13. /**
  14. * The default serialization format to use for testing REST operations.
  15. *
  16. * @var string
  17. */
  18. protected $defaultFormat;
  19. /**
  20. * The default MIME type to use for testing REST operations.
  21. *
  22. * @var string
  23. */
  24. protected $defaultMimeType;
  25. /**
  26. * The entity type to use for testing.
  27. *
  28. * @var string
  29. */
  30. protected $testEntityType = 'entity_test';
  31. /**
  32. * The default authentication provider to use for testing REST operations.
  33. *
  34. * @var array
  35. */
  36. protected $defaultAuth;
  37. /**
  38. * Modules to enable.
  39. *
  40. * @var array
  41. */
  42. public static $modules = array('rest', 'entity_test', 'node');
  43. protected function setUp() {
  44. parent::setUp();
  45. $this->defaultFormat = 'hal_json';
  46. $this->defaultMimeType = 'application/hal+json';
  47. $this->defaultAuth = array('cookie');
  48. // Create a test content type for node testing.
  49. $this->drupalCreateContentType(array('name' => 'resttest', 'type' => 'resttest'));
  50. }
  51. /**
  52. * Helper function to issue a HTTP request with simpletest's cURL.
  53. *
  54. * @param string $url
  55. * The relative URL, e.g. "entity/node/1"
  56. * @param string $method
  57. * HTTP method, one of GET, POST, PUT or DELETE.
  58. * @param array $body
  59. * Either the body for POST and PUT or additional URL parameters for GET.
  60. * @param string $mime_type
  61. * The MIME type of the transmitted content.
  62. */
  63. protected function httpRequest($url, $method, $body = NULL, $mime_type = NULL) {
  64. if (!isset($mime_type)) {
  65. $mime_type = $this->defaultMimeType;
  66. }
  67. if (!in_array($method, array('GET', 'HEAD', 'OPTIONS', 'TRACE'))) {
  68. // GET the CSRF token first for writing requests.
  69. $token = $this->drupalGet('rest/session/token');
  70. }
  71. switch ($method) {
  72. case 'GET':
  73. // Set query if there are additional GET parameters.
  74. $options = isset($body) ? array('absolute' => TRUE, 'query' => $body) : array('absolute' => TRUE);
  75. $curl_options = array(
  76. CURLOPT_HTTPGET => TRUE,
  77. CURLOPT_CUSTOMREQUEST => 'GET',
  78. CURLOPT_URL => url($url, $options),
  79. CURLOPT_NOBODY => FALSE,
  80. CURLOPT_HTTPHEADER => array('Accept: ' . $mime_type),
  81. );
  82. break;
  83. case 'POST':
  84. $curl_options = array(
  85. CURLOPT_HTTPGET => FALSE,
  86. CURLOPT_POST => TRUE,
  87. CURLOPT_POSTFIELDS => $body,
  88. CURLOPT_URL => url($url, array('absolute' => TRUE)),
  89. CURLOPT_NOBODY => FALSE,
  90. CURLOPT_HTTPHEADER => array(
  91. 'Content-Type: ' . $mime_type,
  92. 'X-CSRF-Token: ' . $token,
  93. ),
  94. );
  95. break;
  96. case 'PUT':
  97. $curl_options = array(
  98. CURLOPT_HTTPGET => FALSE,
  99. CURLOPT_CUSTOMREQUEST => 'PUT',
  100. CURLOPT_POSTFIELDS => $body,
  101. CURLOPT_URL => url($url, array('absolute' => TRUE)),
  102. CURLOPT_NOBODY => FALSE,
  103. CURLOPT_HTTPHEADER => array(
  104. 'Content-Type: ' . $mime_type,
  105. 'X-CSRF-Token: ' . $token,
  106. ),
  107. );
  108. break;
  109. case 'PATCH':
  110. $curl_options = array(
  111. CURLOPT_HTTPGET => FALSE,
  112. CURLOPT_CUSTOMREQUEST => 'PATCH',
  113. CURLOPT_POSTFIELDS => $body,
  114. CURLOPT_URL => url($url, array('absolute' => TRUE)),
  115. CURLOPT_NOBODY => FALSE,
  116. CURLOPT_HTTPHEADER => array(
  117. 'Content-Type: ' . $mime_type,
  118. 'X-CSRF-Token: ' . $token,
  119. ),
  120. );
  121. break;
  122. case 'DELETE':
  123. $curl_options = array(
  124. CURLOPT_HTTPGET => FALSE,
  125. CURLOPT_CUSTOMREQUEST => 'DELETE',
  126. CURLOPT_URL => url($url, array('absolute' => TRUE)),
  127. CURLOPT_NOBODY => FALSE,
  128. CURLOPT_HTTPHEADER => array('X-CSRF-Token: ' . $token),
  129. );
  130. break;
  131. }
  132. $response = $this->curlExec($curl_options);
  133. $headers = $this->drupalGetHeaders();
  134. $headers = implode("\n", $headers);
  135. $this->verbose($method . ' request to: ' . $url .
  136. '<hr />Code: ' . curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE) .
  137. '<hr />Response headers: ' . $headers .
  138. '<hr />Response body: ' . $response);
  139. return $response;
  140. }
  141. /**
  142. * Creates entity objects based on their types.
  143. *
  144. * @param string $entity_type
  145. * The type of the entity that should be created.
  146. *
  147. * @return \Drupal\Core\Entity\EntityInterface
  148. * The new entity object.
  149. */
  150. protected function entityCreate($entity_type) {
  151. return entity_create($entity_type, $this->entityValues($entity_type));
  152. }
  153. /**
  154. * Provides an array of suitable property values for an entity type.
  155. *
  156. * Required properties differ from entity type to entity type, so we keep a
  157. * minimum mapping here.
  158. *
  159. * @param string $entity_type
  160. * The type of the entity that should be created.
  161. *
  162. * @return array
  163. * An array of values keyed by property name.
  164. */
  165. protected function entityValues($entity_type) {
  166. switch ($entity_type) {
  167. case 'entity_test':
  168. return array(
  169. 'name' => $this->randomName(),
  170. 'user_id' => 1,
  171. 'field_test_text' => array(0 => array(
  172. 'value' => $this->randomString(),
  173. 'format' => 'plain_text',
  174. )),
  175. );
  176. case 'node':
  177. return array('title' => $this->randomString(), 'type' => 'resttest');
  178. case 'node_type':
  179. return array(
  180. 'type' => 'article',
  181. 'name' => $this->randomName(),
  182. );
  183. case 'user':
  184. return array('name' => $this->randomName());
  185. default:
  186. return array();
  187. }
  188. }
  189. /**
  190. * Enables the REST service interface for a specific entity type.
  191. *
  192. * @param string|FALSE $resource_type
  193. * The resource type that should get REST API enabled or FALSE to disable all
  194. * resource types.
  195. * @param string $method
  196. * The HTTP method to enable, e.g. GET, POST etc.
  197. * @param string $format
  198. * (Optional) The serialization format, e.g. hal_json.
  199. * @param array $auth
  200. * (Optional) The list of valid authentication methods.
  201. */
  202. protected function enableService($resource_type, $method = 'GET', $format = NULL, $auth = NULL) {
  203. // Enable REST API for this entity type.
  204. $config = \Drupal::config('rest.settings');
  205. $settings = array();
  206. if ($resource_type) {
  207. if ($format == NULL) {
  208. $format = $this->defaultFormat;
  209. }
  210. $settings[$resource_type][$method]['supported_formats'][] = $format;
  211. if ($auth == NULL) {
  212. $auth = $this->defaultAuth;
  213. }
  214. $settings[$resource_type][$method]['supported_auth'] = $auth;
  215. }
  216. $config->set('resources', $settings);
  217. $config->save();
  218. $this->rebuildCache();
  219. }
  220. /**
  221. * Rebuilds routing caches.
  222. */
  223. protected function rebuildCache() {
  224. // Rebuild routing cache, so that the REST API paths are available.
  225. $this->container->get('router.builder')->rebuild();
  226. // Reset the Simpletest permission cache, so that the new resource
  227. // permissions get picked up.
  228. drupal_static_reset('checkPermissions');
  229. }
  230. /**
  231. * Check if a HTTP response header exists and has the expected value.
  232. *
  233. * @param string $header
  234. * The header key, example: Content-Type
  235. * @param string $value
  236. * The header value.
  237. * @param string $message
  238. * (optional) A message to display with the assertion.
  239. * @param string $group
  240. * (optional) The group this message is in, which is displayed in a column
  241. * in test output. Use 'Debug' to indicate this is debugging output. Do not
  242. * translate this string. Defaults to 'Other'; most tests do not override
  243. * this default.
  244. *
  245. * @return bool
  246. * TRUE if the assertion succeeded, FALSE otherwise.
  247. */
  248. protected function assertHeader($header, $value, $message = '', $group = 'Browser') {
  249. $header_value = $this->drupalGetHeader($header);
  250. return $this->assertTrue($header_value == $value, $message ? $message : 'HTTP response header ' . $header . ' with value ' . $value . ' found.', $group);
  251. }
  252. /**
  253. * Overrides WebTestBase::drupalLogin().
  254. */
  255. protected function drupalLogin(AccountInterface $user) {
  256. if (isset($this->curlHandle)) {
  257. // cURL quirk: when setting CURLOPT_CUSTOMREQUEST to anything other than
  258. // POST in httpRequest() it has to be restored to POST here. Otherwise the
  259. // POST request to login a user will not work.
  260. curl_setopt($this->curlHandle, CURLOPT_CUSTOMREQUEST, 'POST');
  261. }
  262. parent::drupalLogin($user);
  263. }
  264. /**
  265. * Provides the necessary user permissions for entity operations.
  266. *
  267. * @param string $entity_type
  268. * The entity type.
  269. * @param type $operation
  270. * The operation, one of 'view', 'create', 'update' or 'delete'.
  271. *
  272. * @return array
  273. * The set of user permission strings.
  274. */
  275. protected function entityPermissions($entity_type, $operation) {
  276. switch ($entity_type) {
  277. case 'entity_test':
  278. switch ($operation) {
  279. case 'view':
  280. return array('view test entity');
  281. case 'create':
  282. case 'update':
  283. case 'delete':
  284. return array('administer entity_test content');
  285. }
  286. case 'node':
  287. switch ($operation) {
  288. case 'view':
  289. return array('access content');
  290. case 'create':
  291. return array('create resttest content');
  292. case 'update':
  293. return array('edit any resttest content');
  294. case 'delete':
  295. return array('delete any resttest content');
  296. }
  297. }
  298. }
  299. /**
  300. * Loads an entity based on the location URL returned in the location header.
  301. *
  302. * @param string $location_url
  303. * The URL returned in the Location header.
  304. *
  305. * @return \Drupal\Core\Entity\Entity|FALSE.
  306. * The entity or FALSE if there is no matching entity.
  307. */
  308. protected function loadEntityFromLocationHeader($location_url) {
  309. $url_parts = explode('/', $location_url);
  310. $id = end($url_parts);
  311. return entity_load($this->testEntityType, $id);
  312. }
  313. }