PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/unit-tests/api/webhooks.php

https://gitlab.com/0072016/woocommerce
PHP | 501 lines | 194 code | 126 blank | 181 comment | 0 complexity | 88910829d1d692e25541f85facaf55ae MD5 | raw file
  1. <?php
  2. /**
  3. * Class Webhooks.
  4. * @package WooCommerce\Tests\API
  5. * @since 2.2
  6. */
  7. class WC_Tests_API_Webhooks extends WC_API_Unit_Test_Case {
  8. /** @var WC_API_Webhooks instance */
  9. protected $endpoint;
  10. /** @var WC_Webhook instance */
  11. protected $webhook;
  12. /** @var int webhook delivery (comment) ID */
  13. protected $webhook_delivery_id;
  14. /**
  15. * Setup test webhook data.
  16. *
  17. * @see WC_API_UnitTestCase::setup()
  18. * @since 2.2
  19. */
  20. public function setUp() {
  21. parent::setUp();
  22. $this->endpoint = WC()->api->WC_API_Webhooks;
  23. // mock webhook
  24. $this->webhook = $this->factory->webhook->create_and_get();
  25. // mock webhook delivery
  26. $this->webhook_delivery_id = $this->factory->webhook_delivery->create( array( 'comment_post_ID' => $this->webhook->id ) );
  27. }
  28. /**
  29. * Test route registration.
  30. *
  31. * @since 2.2
  32. */
  33. public function test_register_routes() {
  34. $routes = $this->endpoint->register_routes( array() );
  35. $this->assertArrayHasKey( '/webhooks', $routes );
  36. $this->assertArrayHasKey( '/webhooks/count', $routes );
  37. $this->assertArrayHasKey( '/webhooks/(?P<id>\d+)', $routes );
  38. $this->assertArrayHasKey( '/webhooks/(?P<webhook_id>\d+)/deliveries', $routes );
  39. $this->assertArrayHasKey( '/webhooks/(?P<webhook_id>\d+)/deliveries/(?P<id>\d+)', $routes );
  40. }
  41. /**
  42. * Test GET /webhooks/{id}.
  43. *
  44. * @since 2.2
  45. */
  46. public function test_get_webhook() {
  47. // invalid ID
  48. $response = $this->endpoint->get_webhook( 0 );
  49. $this->assertHasAPIError( 'woocommerce_api_invalid_webhook_id', 404, $response );
  50. // valid request
  51. $response = $this->endpoint->get_webhook( $this->webhook->id );
  52. $this->assertNotWPError( $response );
  53. $this->assertArrayHasKey( 'webhook', $response );
  54. $this->check_get_webhook_response( $response['webhook'], $this->webhook );
  55. }
  56. /**
  57. * Test GET /webhooks/{id} without valid permissions.
  58. *
  59. * @since 2.2
  60. */
  61. public function test_get_webhook_without_permission() {
  62. $this->disable_capability( 'read_private_shop_webhooks' );
  63. $response = $this->endpoint->get_webhook( $this->webhook->id );
  64. $this->assertHasAPIError( 'woocommerce_api_user_cannot_read_webhook', 401, $response );
  65. }
  66. /**
  67. * Test GET /webhooks.
  68. *
  69. * @since 2.2
  70. */
  71. public function test_get_webhooks() {
  72. // valid request
  73. $response = $this->endpoint->get_webhooks( null, null, 'active' );
  74. $this->assertNotWPError( $response );
  75. $this->assertArrayHasKey( 'webhooks', $response );
  76. $this->assertCount( 1, $response['webhooks'] );
  77. $this->check_get_webhook_response( $response['webhooks'][0], $this->webhook );
  78. }
  79. /**
  80. * Test GET /webhooks without valid permissions.
  81. *
  82. * @since 2.2
  83. */
  84. public function test_get_webhooks_without_permission() {
  85. $this->disable_capability( 'read_private_shop_webhooks' );
  86. $response = $this->endpoint->get_webhooks();
  87. $this->assertArrayHasKey( 'webhooks', $response );
  88. $this->assertEmpty( $response['webhooks'] );
  89. }
  90. /**
  91. * Test GET /webhooks/count.
  92. *
  93. * @since 2.2
  94. */
  95. public function test_get_webhooks_count() {
  96. // paused status
  97. $response = $this->endpoint->get_webhooks_count( 'paused' );
  98. $this->assertArrayHasKey( 'count', $response );
  99. $this->assertEquals( 0, $response['count'] );
  100. // disabled status
  101. $response = $this->endpoint->get_webhooks_count( 'disabled' );
  102. $this->assertArrayHasKey( 'count', $response );
  103. $this->assertEquals( 0, $response['count'] );
  104. // an invalid status defaults to 'active'
  105. $response = $this->endpoint->get_webhooks_count( 'bogus' );
  106. $this->assertArrayHasKey( 'count', $response );
  107. $this->assertEquals( 1, $response['count'] );
  108. // valid request
  109. $response = $this->endpoint->get_webhooks_count();
  110. $this->assertArrayHasKey( 'count', $response );
  111. $this->assertEquals( 1, $response['count'] );
  112. }
  113. /**
  114. * Test GET /webhooks/count without valid permissions.
  115. *
  116. * @since 2.2
  117. */
  118. public function test_get_webhooks_count_without_permission() {
  119. // invalid permissions
  120. $this->disable_capability( 'read_private_shop_webhooks' );
  121. $response = $this->endpoint->get_webhooks_count();
  122. $this->assertHasAPIError( 'woocommerce_api_user_cannot_read_webhooks_count', 401, $response );
  123. }
  124. /**
  125. * Test POST /webhooks.
  126. *
  127. * @since 2.2
  128. */
  129. public function test_create_webhook() {
  130. $response = $this->endpoint->create_webhook( $this->get_defaults() );
  131. $this->check_create_webhook_response( $response );
  132. }
  133. /**
  134. * Test POST /webhooks without valid permissions.
  135. *
  136. * @since 2.2
  137. */
  138. public function test_create_webhook_without_permission() {
  139. $this->disable_capability( 'publish_shop_webhooks' );
  140. $response = $this->endpoint->create_webhook( $this->get_defaults() );
  141. $this->assertHasAPIError( 'woocommerce_api_user_cannot_create_webhooks', 401, $response );
  142. }
  143. /**
  144. * Test POST /webhooks with custom topic.
  145. *
  146. * @since 2.2
  147. */
  148. public function test_create_webhook_custom_topic() {
  149. $response = $this->endpoint->create_webhook( $this->get_defaults( array( 'topic' => 'action.woocommerce_cart_updated' ) ) );
  150. $this->check_edit_webhook_response( $response );
  151. }
  152. /**
  153. * Test an invalid or empty topic for POST /webhooks.
  154. *
  155. * @since 2.2
  156. */
  157. public function test_create_webhook_invalid_topic() {
  158. // empty
  159. $response = $this->endpoint->create_webhook( $this->get_defaults( array( 'topic' => null ) ) );
  160. $this->assertHasAPIError( 'woocommerce_api_invalid_webhook_topic', 400, $response );
  161. // invalid - missing event
  162. $response = $this->endpoint->create_webhook( $this->get_defaults( array( 'topic' => 'invalid' ) ) );
  163. $this->assertHasAPIError( 'woocommerce_api_invalid_webhook_topic', 400, $response );
  164. // invalid
  165. $response = $this->endpoint->create_webhook( $this->get_defaults( array( 'topic' => 'invalid.topic' ) ) );
  166. $this->assertHasAPIError( 'woocommerce_api_invalid_webhook_topic', 400, $response );
  167. }
  168. /**
  169. * Test an invalid or empty delivery for POST /webhooks.
  170. *
  171. * @since 2.2
  172. */
  173. public function test_create_webhook_invalid_delivery_url() {
  174. // empty
  175. $response = $this->endpoint->create_webhook( $this->get_defaults( array( 'delivery_url' => null ) ) );
  176. $this->assertHasAPIError( 'woocommerce_api_invalid_webhook_delivery_url', 400, $response );
  177. // invalid - scheme must be HTTP or HTTPS
  178. $response = $this->endpoint->create_webhook( $this->get_defaults( array( 'delivery_url' => 'foo://bar' ) ) );
  179. $this->assertHasAPIError( 'woocommerce_api_invalid_webhook_delivery_url', 400, $response );
  180. // invalid - must be valid URL
  181. $response = $this->endpoint->create_webhook( $this->get_defaults( array( 'delivery_url' => 'https://foobar!' ) ) );
  182. $this->assertHasAPIError( 'woocommerce_api_invalid_webhook_delivery_url', 400, $response );
  183. }
  184. /**
  185. * Test wp_insert_post() failure for POST /webhooks.
  186. *
  187. * @since 2.2
  188. */
  189. public function test_create_webhook_insert_post_failure() {
  190. add_filter( 'wp_insert_post_empty_content', '__return_true' );
  191. $response = $this->endpoint->create_webhook( $this->get_defaults() );
  192. $this->assertHasAPIError( 'woocommerce_api_cannot_create_webhook', 500, $response );
  193. }
  194. /**
  195. * Test PUT /webhooks/{id}.
  196. *
  197. * @since 2.2
  198. */
  199. public function test_edit_webhook() {
  200. // invalid ID
  201. $response = $this->endpoint->edit_webhook( 0, $this->get_defaults() );
  202. $this->assertHasAPIError( 'woocommerce_api_invalid_webhook_id', 404, $response );
  203. $args = array(
  204. 'secret' => rand_str(),
  205. 'status' => 'paused',
  206. );
  207. // valid request
  208. $response = $this->endpoint->edit_webhook( $this->webhook->id, $this->get_defaults( $args ) );
  209. $this->check_edit_webhook_response( $response );
  210. }
  211. /**
  212. * Test PUT /webhooks/{id} without valid permissions.
  213. *
  214. * @since 2.2
  215. */
  216. public function test_edit_webhook_without_permission() {
  217. $this->disable_capability( 'edit_published_shop_webhooks' );
  218. $response = $this->endpoint->edit_webhook( $this->webhook->id, $this->get_defaults() );
  219. $this->assertHasAPIError( 'woocommerce_api_user_cannot_edit_webhook', 401, $response );
  220. }
  221. /**
  222. * Test PUT /webhooks/{id} with updated topic.
  223. *
  224. * @since 2.2
  225. */
  226. public function test_edit_webhook_change_topic() {
  227. // invalid topic
  228. $response = $this->endpoint->edit_webhook( $this->webhook->id, $this->get_defaults( array( 'topic' => 'invalid.topic' ) ) );
  229. $this->assertHasAPIError( 'woocommerce_api_invalid_webhook_topic', 400, $response );
  230. // valid request
  231. $response = $this->endpoint->edit_webhook( $this->webhook->id, $this->get_defaults( array( 'topic' => 'order.updated' ) ) );
  232. $this->check_edit_webhook_response( $response );
  233. }
  234. /**
  235. * Test PUT /webhooks/{id} with updated delivery URL.
  236. *
  237. * @since 2.2
  238. */
  239. public function test_edit_webhook_change_delivery_url() {
  240. // invalid delivery URL
  241. $response = $this->endpoint->edit_webhook( $this->webhook->id, $this->get_defaults( array( 'delivery_url' => 'foo://bar' ) ) );
  242. $this->assertHasAPIError( 'woocommerce_api_invalid_webhook_delivery_url', 400, $response );
  243. // valid request
  244. $response = $this->endpoint->edit_webhook( $this->webhook->id, $this->get_defaults( array( 'delivery_url' => 'http://www.skyverge.com' ) ) );
  245. $this->check_edit_webhook_response( $response );
  246. }
  247. /**
  248. * Test DELETE /webhooks/{id}.
  249. *
  250. * @since 2.2
  251. */
  252. public function test_delete_webhook() {
  253. // invalid ID
  254. $response = $this->endpoint->delete_webhook( 0 );
  255. $this->assertHasAPIError( 'woocommerce_api_invalid_webhook_id', 404, $response );
  256. // valid request
  257. $response = $this->endpoint->delete_webhook( $this->webhook->id );
  258. $this->assertArrayHasKey( 'message', $response );
  259. $this->assertEquals( 'Permanently deleted webhook', $response['message'] );
  260. }
  261. /**
  262. * Test GET /webhooks/{id}/deliveries.
  263. *
  264. * @since 2.2
  265. */
  266. public function test_get_webhook_deliveries() {
  267. // invalid ID
  268. $response = $this->endpoint->get_webhook_deliveries( 0 );
  269. $this->assertHasAPIError( 'woocommerce_api_invalid_webhook_id', '404', $response );
  270. // valid request
  271. $response = $this->endpoint->get_webhook_deliveries( $this->webhook->id );
  272. $this->assertNotWPError( $response );
  273. $this->assertArrayHasKey( 'webhook_deliveries', $response );
  274. $this->assertCount( 1, $response['webhook_deliveries'] );
  275. $this->check_get_webhook_delivery_response( $response['webhook_deliveries'][0], $this->webhook->get_delivery_log( $response['webhook_deliveries'][0]['id'] ) );
  276. }
  277. /**
  278. * Test GET /webhooks/{id}/deliveries/{id}.
  279. *
  280. * @since 2.2
  281. */
  282. public function test_get_webhook_delivery() {
  283. $response = $this->endpoint->get_webhook_delivery( $this->webhook->id, $this->webhook_delivery_id );
  284. $this->assertNotWPError( $response );
  285. $this->assertArrayHasKey( 'webhook_delivery', $response );
  286. $this->assertNotEmpty( $response['webhook_delivery'] );
  287. $this->check_get_webhook_delivery_response( $response['webhook_delivery'], $this->webhook->get_delivery_log( $response['webhook_delivery']['id'] ) );
  288. }
  289. /**
  290. * Test GET /webhooks/{id}/deliveries/{id} with invalid webhook & delivery IDs.
  291. *
  292. * @since 2.2
  293. */
  294. public function test_get_webhook_delivery_invalid_ids() {
  295. // invalid webhook ID
  296. $response = $this->endpoint->get_webhook_delivery( 0, 0 );
  297. $this->assertHasAPIError( 'woocommerce_api_invalid_webhook_id', 404, $response );
  298. // invalid delivery ID
  299. $response = $this->endpoint->get_webhook_delivery( $this->webhook->id, 0 );
  300. $this->assertHasAPIError( 'woocommerce_api_invalid_webhook_delivery_id', 404, $response );
  301. $post_id = $this->factory->post->create();
  302. $mock_comment_id = $this->factory->comment->create( array( 'comment_post_ID' => $post_id ) );
  303. // invalid delivery (valid comment, but not the correct type)
  304. $response = $this->endpoint->get_webhook_delivery( $this->webhook->id, $mock_comment_id );
  305. $this->assertHasAPIError( 'woocommerce_api_invalid_webhook_delivery_id', 400, $response );
  306. }
  307. /**
  308. * Get default arguments for creating/editing a webhook.
  309. *
  310. * @since 2.2
  311. * @param array $args
  312. * @return array
  313. */
  314. protected function get_defaults( $args = array() ) {
  315. $defaults = array(
  316. 'name' => rand_str(),
  317. 'topic' => 'coupon.created',
  318. 'delivery_url' => 'http://example.org',
  319. );
  320. return array( 'webhook' => wp_parse_args( $args, $defaults ) );
  321. }
  322. /**
  323. * Ensure a valid response when creating a webhook.
  324. * @since 2.2
  325. * @param $response
  326. */
  327. protected function check_create_webhook_response( $response ) {
  328. $this->assertNotWPError( $response );
  329. $this->assertArrayHasKey( 'webhook', $response );
  330. $this->check_get_webhook_response( $response['webhook'], new WC_Webhook( $response['webhook']['id'] ) );
  331. }
  332. /**
  333. * Ensure a valid response after editing a webhook.
  334. *
  335. * @since 2.2
  336. * @param $response
  337. */
  338. protected function check_edit_webhook_response( $response ) {
  339. $this->assertNotWPError( $response );
  340. $this->assertArrayHasKey( 'webhook', $response );
  341. $this->check_get_webhook_response( $response['webhook'], new WC_Webhook( $response['webhook']['id'] ) );
  342. }
  343. /**
  344. * Ensure valid webhook data response.
  345. *
  346. * @since 2.2
  347. * @param array $response
  348. * @param WC_Webhook $webhook
  349. */
  350. protected function check_get_webhook_response( $response, $webhook ) {
  351. $this->assertEquals( $webhook->id, $response['id'] );
  352. $this->assertEquals( $webhook->get_name(), $response['name'] );
  353. $this->assertEquals( $webhook->get_status() , $response['status'] );
  354. $this->assertEquals( $webhook->get_topic(), $response['topic'] );
  355. $this->assertEquals( $webhook->get_resource(), $response['resource'] );
  356. $this->assertEquals( $webhook->get_event(), $response['event'] );
  357. $this->assertEquals( $webhook->get_hooks(), $response['hooks'] );
  358. $this->assertEquals( $webhook->get_delivery_url(), $response['delivery_url'] );
  359. $this->assertArrayHasKey( 'created_at', $response );
  360. $this->assertArrayHasKey( 'updated_at', $response );
  361. }
  362. /**
  363. * Ensure valid webhook delivery response.
  364. *
  365. * @since 2.2
  366. * @param array $response
  367. * @param array $delivery
  368. */
  369. protected function check_get_webhook_delivery_response( $response, $delivery ) {
  370. // normalize data
  371. unset( $response['created_at'] );
  372. unset( $delivery['comment'] );
  373. $this->assertEquals( $delivery, $response );
  374. }
  375. }