TaskTest

Copyright 2014 Google Inc.

Defined (1)

The class is defined in the following location(s).

/vendor/google/apiclient/tests/general/TaskTest.php  
  1. class TaskTest extends PHPUnit_Framework_TestCase 
  2. private $client; 
  3.  
  4. private $mockedCallsCount = 0; 
  5. private $currentMockedCall = 0; 
  6. private $mockedCalls = array(); 
  7.  
  8. protected function setUp() 
  9. $this->client = new Google_Client(); 
  10.  
  11. /** 
  12. * @dataProvider defaultRestErrorProvider 
  13. * @expectedException Google_Service_Exception 
  14. */ 
  15. public function testRestRetryOffByDefault($errorCode, $errorBody = '{}') 
  16. $this->setNextResponse($errorCode, $errorBody)->makeRequest(); 
  17.  
  18. /** 
  19. * @dataProvider defaultRestErrorProvider 
  20. * @expectedException Google_Service_Exception 
  21. */ 
  22. public function testOneRestRetryWithError($errorCode, $errorBody = '{}') 
  23. $this->setTaskConfig(array('retries' => 1)); 
  24. $this->setNextResponses(2, $errorCode, $errorBody)->makeRequest(); 
  25.  
  26. /** 
  27. * @dataProvider defaultRestErrorProvider 
  28. * @expectedException Google_Service_Exception 
  29. */ 
  30. public function testMultipleRestRetriesWithErrors( 
  31. $errorCode,  
  32. $errorBody = '{}' 
  33. ) { 
  34. $this->setTaskConfig(array('retries' => 5)); 
  35. $this->setNextResponses(6, $errorCode, $errorBody)->makeRequest(); 
  36.  
  37. /** 
  38. * @dataProvider defaultRestErrorProvider 
  39. */ 
  40. public function testOneRestRetryWithSuccess($errorCode, $errorBody = '{}') 
  41. $this->setTaskConfig(array('retries' => 1)); 
  42. $result = $this->setNextResponse($errorCode, $errorBody) 
  43. ->setNextResponse(200, '{"success": true}') 
  44. ->makeRequest(); 
  45.  
  46. $this->assertEquals(array("success" => true), $result); 
  47.  
  48. /** 
  49. * @dataProvider defaultRestErrorProvider 
  50. */ 
  51. public function testMultipleRestRetriesWithSuccess( 
  52. $errorCode,  
  53. $errorBody = '{}' 
  54. ) { 
  55. $this->setTaskConfig(array('retries' => 5)); 
  56. $result = $this->setNextResponses(2, $errorCode, $errorBody) 
  57. ->setNextResponse(200, '{"success": true}') 
  58. ->makeRequest(); 
  59.  
  60. $this->assertEquals(array("success" => true), $result); 
  61.  
  62. /** 
  63. * @dataProvider defaultRestErrorProvider 
  64. * @expectedException Google_Service_Exception 
  65. */ 
  66. public function testCustomRestRetryMapReplacesDefaults( 
  67. $errorCode,  
  68. $errorBody = '{}' 
  69. ) { 
  70. $this->client->setClassConfig( 
  71. 'Google_Service_Exception',  
  72. array('retry_map' => array()) 
  73. ); 
  74.  
  75. $this->setTaskConfig(array('retries' => 5)); 
  76. $this->setNextResponse($errorCode, $errorBody)->makeRequest(); 
  77.  
  78. public function testCustomRestRetryMapAddsNewHandlers() 
  79. $this->client->setClassConfig( 
  80. 'Google_Service_Exception',  
  81. array('retry_map' => array('403' => Google_Config::TASK_RETRY_ALWAYS)) 
  82. ); 
  83.  
  84. $this->setTaskConfig(array('retries' => 5)); 
  85. $result = $this->setNextResponses(2, 403) 
  86. ->setNextResponse(200, '{"success": true}') 
  87. ->makeRequest(); 
  88.  
  89. $this->assertEquals(array("success" => true), $result); 
  90.  
  91. /** 
  92. * @expectedException Google_Service_Exception 
  93. * @dataProvider customLimitsProvider 
  94. */ 
  95. public function testCustomRestRetryMapWithCustomLimits($limit) 
  96. $this->client->setClassConfig( 
  97. 'Google_Service_Exception',  
  98. array('retry_map' => array('403' => $limit)) 
  99. ); 
  100.  
  101. $this->setTaskConfig(array('retries' => 5)); 
  102. $this->setNextResponses($limit + 1, 403)->makeRequest(); 
  103.  
  104. /** 
  105. * @dataProvider timeoutProvider 
  106. */ 
  107. public function testRestTimeouts($config, $minTime) 
  108. $this->setTaskConfig($config); 
  109. $this->setNextResponses($config['retries'], 500) 
  110. ->setNextResponse(200, '{"success": true}'); 
  111.  
  112. $this->assertTaskTimeGreaterThanOrEqual( 
  113. $minTime,  
  114. array($this, 'makeRequest'),  
  115. $config['initial_delay'] / 10 
  116. ); 
  117.  
  118. /** 
  119. * @requires extension curl 
  120. * @dataProvider defaultCurlErrorProvider 
  121. * @expectedException Google_IO_Exception 
  122. */ 
  123. public function testCurlRetryOffByDefault($errorCode, $errorMessage = '') 
  124. $this->setNextResponseThrows($errorMessage, $errorCode)->makeRequest(); 
  125.  
  126. /** 
  127. * @requires extension curl 
  128. * @dataProvider defaultCurlErrorProvider 
  129. * @expectedException Google_IO_Exception 
  130. */ 
  131. public function testOneCurlRetryWithError($errorCode, $errorMessage = '') 
  132. $this->setTaskConfig(array('retries' => 1)); 
  133. $this->setNextResponsesThrow(2, $errorMessage, $errorCode)->makeRequest(); 
  134.  
  135. /** 
  136. * @requires extension curl 
  137. * @dataProvider defaultCurlErrorProvider 
  138. * @expectedException Google_IO_Exception 
  139. */ 
  140. public function testMultipleCurlRetriesWithErrors( 
  141. $errorCode,  
  142. $errorMessage = '' 
  143. ) { 
  144. $this->setTaskConfig(array('retries' => 5)); 
  145. $this->setNextResponsesThrow(6, $errorMessage, $errorCode)->makeRequest(); 
  146.  
  147. /** 
  148. * @requires extension curl 
  149. * @dataProvider defaultCurlErrorProvider 
  150. */ 
  151. public function testOneCurlRetryWithSuccess($errorCode, $errorMessage = '') 
  152. $this->setTaskConfig(array('retries' => 1)); 
  153. $result = $this->setNextResponseThrows($errorMessage, $errorCode) 
  154. ->setNextResponse(200, '{"success": true}') 
  155. ->makeRequest(); 
  156.  
  157. $this->assertEquals(array("success" => true), $result); 
  158.  
  159. /** 
  160. * @requires extension curl 
  161. * @dataProvider defaultCurlErrorProvider 
  162. */ 
  163. public function testMultipleCurlRetriesWithSuccess( 
  164. $errorCode,  
  165. $errorMessage = '' 
  166. ) { 
  167. $this->setTaskConfig(array('retries' => 5)); 
  168. $result = $this->setNextResponsesThrow(2, $errorMessage, $errorCode) 
  169. ->setNextResponse(200, '{"success": true}') 
  170. ->makeRequest(); 
  171.  
  172. $this->assertEquals(array("success" => true), $result); 
  173.  
  174. /** 
  175. * @requires extension curl 
  176. * @dataProvider defaultCurlErrorProvider 
  177. * @expectedException Google_IO_Exception 
  178. */ 
  179. public function testCustomCurlRetryMapReplacesDefaults( 
  180. $errorCode,  
  181. $errorMessage = '' 
  182. ) { 
  183. $this->client->setClassConfig( 
  184. 'Google_IO_Exception',  
  185. array('retry_map' => array()) 
  186. ); 
  187.  
  188. $this->setTaskConfig(array('retries' => 5)); 
  189. $this->setNextResponseThrows($errorMessage, $errorCode)->makeRequest(); 
  190.  
  191. /** 
  192. * @requires extension curl 
  193. */ 
  194. public function testCustomCurlRetryMapAddsNewHandlers() 
  195. $this->client->setClassConfig( 
  196. 'Google_IO_Exception',  
  197. array('retry_map' => array( 
  198. CURLE_COULDNT_RESOLVE_PROXY => Google_Config::TASK_RETRY_ALWAYS 
  199. )) 
  200. ); 
  201.  
  202. $this->setTaskConfig(array('retries' => 5)); 
  203. $result = $this->setNextResponsesThrow(2, '', CURLE_COULDNT_RESOLVE_PROXY) 
  204. ->setNextResponse(200, '{"success": true}') 
  205. ->makeRequest(); 
  206.  
  207. $this->assertEquals(array("success" => true), $result); 
  208.  
  209. /** 
  210. * @requires extension curl 
  211. * @expectedException Google_IO_Exception 
  212. * @dataProvider customLimitsProvider 
  213. */ 
  214. public function testCustomCurlRetryMapWithCustomLimits($limit) 
  215. $this->client->setClassConfig( 
  216. 'Google_IO_Exception',  
  217. array('retry_map' => array( 
  218. CURLE_COULDNT_RESOLVE_PROXY => $limit 
  219. )) 
  220. ); 
  221.  
  222. $this->setTaskConfig(array('retries' => 5)); 
  223. $this->setNextResponsesThrow($limit + 1, '', CURLE_COULDNT_RESOLVE_PROXY) 
  224. ->makeRequest(); 
  225.  
  226. /** 
  227. * @requires extension curl 
  228. * @dataProvider timeoutProvider 
  229. */ 
  230. public function testCurlTimeouts($config, $minTime) 
  231. $this->setTaskConfig($config); 
  232. $this->setNextResponsesThrow($config['retries'], '', CURLE_GOT_NOTHING) 
  233. ->setNextResponse(200, '{"success": true}'); 
  234.  
  235. $this->assertTaskTimeGreaterThanOrEqual( 
  236. $minTime,  
  237. array($this, 'makeRequest'),  
  238. $config['initial_delay'] / 10 
  239. ); 
  240.  
  241. /** 
  242. * @dataProvider badTaskConfigProvider 
  243. */ 
  244. public function testBadTaskConfig($config, $message) 
  245. $this->setExpectedException('Google_Task_Exception', $message); 
  246. $this->setTaskConfig($config); 
  247.  
  248. new Google_Task_Runner( 
  249. $this->client,  
  250. '',  
  251. array($this, 'testBadTaskConfig') 
  252. ); 
  253.  
  254. /** 
  255. * @expectedException Google_Task_Exception 
  256. * @expectedExceptionMessage must be a valid callable 
  257. */ 
  258. public function testBadTaskCallback() 
  259. new Google_Task_Runner($this->client, '', 5); 
  260.  
  261. /** 
  262. * @expectedException Google_IO_Exception 
  263. */ 
  264. public function testTaskRetryOffByDefault() 
  265. $this->setNextTaskAllowedRetries(Google_Config::TASK_RETRY_ALWAYS) 
  266. ->runTask(); 
  267.  
  268. /** 
  269. * @expectedException Google_IO_Exception 
  270. */ 
  271. public function testOneTaskRetryWithError() 
  272. $this->setTaskConfig(array('retries' => 1)); 
  273. $this->setNextTasksAllowedRetries(2, Google_Config::TASK_RETRY_ALWAYS) 
  274. ->runTask(); 
  275.  
  276. /** 
  277. * @expectedException Google_IO_Exception 
  278. */ 
  279. public function testMultipleTaskRetriesWithErrors() 
  280. $this->setTaskConfig(array('retries' => 5)); 
  281. $this->setNextTasksAllowedRetries(6, Google_Config::TASK_RETRY_ALWAYS) 
  282. ->runTask(); 
  283.  
  284. public function testOneTaskRetryWithSuccess() 
  285. $this->setTaskConfig(array('retries' => 1)); 
  286. $result = $this->setNextTaskAllowedRetries(Google_Config::TASK_RETRY_ALWAYS) 
  287. ->setNextTaskReturnValue('success') 
  288. ->runTask(); 
  289.  
  290. $this->assertEquals('success', $result); 
  291.  
  292. public function testMultipleTaskRetriesWithSuccess() 
  293. $this->setTaskConfig(array('retries' => 5)); 
  294. $result = $this->setNextTasksAllowedRetries(2, Google_Config::TASK_RETRY_ALWAYS) 
  295. ->setNextTaskReturnValue('success') 
  296. ->runTask(); 
  297.  
  298. $this->assertEquals('success', $result); 
  299.  
  300. /** 
  301. * @expectedException Google_IO_Exception 
  302. * @dataProvider customLimitsProvider 
  303. */ 
  304. public function testTaskRetryWithCustomLimits($limit) 
  305. $this->setTaskConfig(array('retries' => 5)); 
  306. $this->setNextTasksAllowedRetries($limit + 1, $limit) 
  307. ->runTask(); 
  308.  
  309. /** 
  310. * @dataProvider timeoutProvider 
  311. */ 
  312. public function testTaskTimeouts($config, $minTime) 
  313. $this->setTaskConfig($config); 
  314. $this->setNextTasksAllowedRetries($config['retries'], $config['retries'] + 1) 
  315. ->setNextTaskReturnValue('success'); 
  316.  
  317. $this->assertTaskTimeGreaterThanOrEqual( 
  318. $minTime,  
  319. array($this, 'runTask'),  
  320. $config['initial_delay'] / 10 
  321. ); 
  322.  
  323. public function testTaskWithManualRetries() 
  324. $this->setTaskConfig(array('retries' => 2)); 
  325. $this->setNextTasksAllowedRetries(2, Google_Config::TASK_RETRY_ALWAYS); 
  326.  
  327. $task = new Google_Task_Runner( 
  328. $this->client,  
  329. '',  
  330. array($this, 'runNextTask') 
  331. ); 
  332.  
  333. $this->assertTrue($task->canAttmpt()); 
  334. $this->assertTrue($task->attempt()); 
  335.  
  336. $this->assertTrue($task->canAttmpt()); 
  337. $this->assertTrue($task->attempt()); 
  338.  
  339. $this->assertTrue($task->canAttmpt()); 
  340. $this->assertTrue($task->attempt()); 
  341.  
  342. $this->assertFalse($task->canAttmpt()); 
  343. $this->assertFalse($task->attempt()); 
  344.  
  345. /** 
  346. * Provider for backoff configurations and expected minimum runtimes. 
  347. * @return array 
  348. */ 
  349. public function timeoutProvider() 
  350. $config = array('initial_delay' => .001, 'max_delay' => .01); 
  351.  
  352. return array( 
  353. array(array_merge($config, array('retries' => 1)), .001),  
  354. array(array_merge($config, array('retries' => 2)), .0015),  
  355. array(array_merge($config, array('retries' => 3)), .00225),  
  356. array(array_merge($config, array('retries' => 4)), .00375),  
  357. array(array_merge($config, array('retries' => 5)), .005625) 
  358. ); 
  359.  
  360. /** 
  361. * Provider for custom retry limits. 
  362. * @return array 
  363. */ 
  364. public function customLimitsProvider() 
  365. return array( 
  366. array(Google_Config::TASK_RETRY_NEVER),  
  367. array(Google_Config::TASK_RETRY_ONCE),  
  368. ); 
  369.  
  370. /** 
  371. * Provider for invalid task configurations. 
  372. * @return array 
  373. */ 
  374. public function badTaskConfigProvider() 
  375. return array( 
  376. array(array('initial_delay' => -1), 'must not be negative'),  
  377. array(array('max_delay' => 0), 'must be greater than 0'),  
  378. array(array('factor' => 0), 'must be greater than 0'),  
  379. array(array('jitter' => 0), 'must be greater than 0'),  
  380. array(array('retries' => -1), 'must not be negative') 
  381. ); 
  382.  
  383. /** 
  384. * Provider for the default REST errors. 
  385. * @return array 
  386. */ 
  387. public function defaultRestErrorProvider() 
  388. return array( 
  389. array(500),  
  390. array(503),  
  391. array(403, '{"error":{"errors":[{"reason":"rateLimitExceeded"}]}}'),  
  392. array(403, '{"error":{"errors":[{"reason":"userRateLimitExceeded"}]}}'),  
  393. ); 
  394.  
  395. /** 
  396. * Provider for the default cURL errors. 
  397. * @return array 
  398. */ 
  399. public function defaultCurlErrorProvider() 
  400. return array( 
  401. array(6), // CURLE_COULDNT_RESOLVE_HOST 
  402. array(7), // CURLE_COULDNT_CONNECT 
  403. array(28), // CURLE_OPERATION_TIMEOUTED 
  404. array(35), // CURLE_SSL_CONNECT_ERROR 
  405. array(52), // CURLE_GOT_NOTHING 
  406. ); 
  407.  
  408. /** 
  409. * Assert the minimum amount of time required to run a task. 
  410. * NOTE: Intentionally crude for brevity. 
  411. * @param float $expected The expected minimum execution time 
  412. * @param callable $callback The task to time 
  413. * @param float $delta Allowable relative error 
  414. * @throws PHPUnit_Framework_ExpectationFailedException 
  415. */ 
  416. public static function assertTaskTimeGreaterThanOrEqual( 
  417. $expected,  
  418. $callback,  
  419. $delta = 0.0 
  420. ) { 
  421. $time = microtime(true); 
  422.  
  423. call_user_func($callback); 
  424.  
  425. self::assertThat( 
  426. microtime(true) - $time,  
  427. self::logicalOr( 
  428. self::greaterThan($expected),  
  429. self::equalTo($expected, $delta) 
  430. ); 
  431.  
  432. /** 
  433. * Sets the task runner configurations. 
  434. * @param array $config The task runner configurations 
  435. */ 
  436. private function setTaskConfig(array $config) 
  437. $config += array( 
  438. 'initial_delay' => .0001,  
  439. 'max_delay' => .001,  
  440. 'factor' => 2,  
  441. 'jitter' => .5,  
  442. 'retries' => 1 
  443. ); 
  444. $this->client->setClassConfig('Google_Task_Runner', $config); 
  445.  
  446. /** 
  447. * Sets the next responses. 
  448. * @param integer $count The number of responses 
  449. * @param string $code The response code 
  450. * @param string $body The response body 
  451. * @param array $headers The response headers 
  452. * @return TaskTest 
  453. */ 
  454. private function setNextResponses( 
  455. $count,  
  456. $code = '200',  
  457. $body = '{}',  
  458. array $headers = array() 
  459. ) { 
  460. while ($count-- > 0) { 
  461. $this->setNextResponse($code, $body, $headers); 
  462.  
  463. return $this; 
  464.  
  465. /** 
  466. * Sets the next response. 
  467. * @param string $code The response code 
  468. * @param string $body The response body 
  469. * @param array $headers The response headers 
  470. * @return TaskTest 
  471. */ 
  472. private function setNextResponse( 
  473. $code = '200',  
  474. $body = '{}',  
  475. array $headers = array() 
  476. ) { 
  477. $this->mockedCalls[$this->mockedCallsCount++] = array( 
  478. 'code' => (string) $code,  
  479. 'headers' => $headers,  
  480. 'body' => is_string($body) ? $body : json_encode($body) 
  481. ); 
  482.  
  483. return $this; 
  484.  
  485. /** 
  486. * Forces the next responses to throw an IO exception. 
  487. * @param integer $count The number of responses 
  488. * @param string $message The exception messages 
  489. * @param string $code The exception code 
  490. * @return TaskTest 
  491. */ 
  492. private function setNextResponsesThrow($count, $message, $code) 
  493. while ($count-- > 0) { 
  494. $this->setNextResponseThrows($message, $code); 
  495.  
  496. return $this; 
  497.  
  498. /** 
  499. * Forces the next response to throw an IO exception. 
  500. * @param string $message The exception messages 
  501. * @param string $code The exception code 
  502. * @return TaskTest 
  503. */ 
  504. private function setNextResponseThrows($message, $code) 
  505. $map = $this->client->getClassConfig('Google_IO_Exception', 'retry_map'); 
  506. $this->mockedCalls[$this->mockedCallsCount++] = new Google_IO_Exception( 
  507. $message,  
  508. $code,  
  509. null,  
  510. $map 
  511. ); 
  512.  
  513. return $this; 
  514.  
  515. /** 
  516. * Runs the defined request. 
  517. * @return array 
  518. */ 
  519. private function makeRequest() 
  520. $request = new Google_Http_Request('/test'); 
  521.  
  522. $io = $this->getMockBuilder('Google_IO_Abstract') 
  523. ->disableOriginalConstructor() 
  524. ->setMethods(array('makeRequest')) 
  525. ->getMockForAbstractClass(); 
  526.  
  527. $io->expects($this->exactly($this->mockedCallsCount)) 
  528. ->method('makeRequest') 
  529. ->will($this->returnCallback(array($this, 'getNextMockedCall'))); 
  530.  
  531. $this->client->setIo($io); 
  532.  
  533. return Google_Http_REST::execute($this->client, $request); 
  534.  
  535. /** 
  536. * Gets the next mocked response. 
  537. * @param Google_Http_Request $request The mocked request 
  538. * @return Google_Http_Request 
  539. */ 
  540. public function getNextMockedCall($request) 
  541. $current = $this->mockedCalls[$this->currentMockedCall++]; 
  542.  
  543. if ($current instanceof Exception) { 
  544. throw $current; 
  545.  
  546. $request->setResponseHttpCode($current['code']); 
  547. $request->setResponseHeaders($current['headers']); 
  548. $request->setResponseBody($current['body']); 
  549.  
  550. return $request; 
  551.  
  552. /** 
  553. * Sets the next task return value. 
  554. * @param mixed $value The next return value 
  555. * @return TaskTest 
  556. */ 
  557. private function setNextTaskReturnValue($value) 
  558. $this->mockedCalls[$this->mockedCallsCount++] = $value; 
  559. return $this; 
  560.  
  561. /** 
  562. * Sets the next exception `allowedRetries()` return value. 
  563. * @param boolean $allowedRetries The next `allowedRetries()` return value. 
  564. * @return TaskTest 
  565. */ 
  566. private function setNextTaskAllowedRetries($allowedRetries) 
  567. $this->mockedCalls[$this->mockedCallsCount++] = $allowedRetries; 
  568. return $this; 
  569.  
  570. /** 
  571. * Sets multiple exception `allowedRetries()` return value. 
  572. * @param integer $count The number of `allowedRetries()` return values. 
  573. * @param boolean $allowedRetries The `allowedRetries()` return value. 
  574. * @return TaskTest 
  575. */ 
  576. private function setNextTasksAllowedRetries($count, $allowedRetries) 
  577. while ($count-- > 0) { 
  578. $this->setNextTaskAllowedRetries($allowedRetries); 
  579.  
  580. return $this; 
  581.  
  582. /** 
  583. * Runs the defined task. 
  584. * @return mixed 
  585. */ 
  586. private function runTask() 
  587. $task = new Google_Task_Runner( 
  588. $this->client,  
  589. '',  
  590. array($this, 'runNextTask') 
  591. ); 
  592.  
  593. $exception = $this->getMockBuilder('Google_IO_Exception') 
  594. ->disableOriginalConstructor() 
  595. ->setMethods(array('allowedRetries')) 
  596. ->getMock(); 
  597. $exceptionCount = 0; 
  598. $exceptionCalls = array(); 
  599.  
  600. for ($i = 0; $i < $this->mockedCallsCount; $i++) { 
  601. if (is_int($this->mockedCalls[$i])) { 
  602. $exceptionCalls[$exceptionCount++] = $this->mockedCalls[$i]; 
  603. $this->mockedCalls[$i] = $exception; 
  604.  
  605. $exception->expects($this->exactly($exceptionCount)) 
  606. ->method('allowedRetries') 
  607. ->will( 
  608. new PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls( 
  609. $exceptionCalls 
  610. ); 
  611.  
  612. return $task->run(); 
  613.  
  614. /** 
  615. * Gets the next task return value. 
  616. * @return mixed 
  617. */ 
  618. public function runNextTask() 
  619. $current = $this->mockedCalls[$this->currentMockedCall++]; 
  620.  
  621. if ($current instanceof Exception) { 
  622. throw $current; 
  623.  
  624. return $current;