Open Monograph Press  3.3.0
CurlMultiTest.php
1 <?php
2 
3 namespace Guzzle\Tests\Http\Curl;
4 
15 
21 {
23  private $multi;
24 
28  protected function setUp()
29  {
30  parent::setUp();
31  $this->multi = new MockMulti();
32  }
33 
34  public function tearDown()
35  {
36  unset($this->multi);
37  }
38 
39  public function testConstructorCreateMultiHandle()
40  {
41  $this->assertInternalType('resource', $this->multi->getHandle());
42  $this->assertEquals('curl_multi', get_resource_type($this->multi->getHandle()));
43  }
44 
45  public function testDestructorClosesMultiHandle()
46  {
47  $handle = $this->multi->getHandle();
48  $this->multi->__destruct();
49  $this->assertFalse(is_resource($handle));
50  }
51 
52  public function testRequestsCanBeAddedAndCounted()
53  {
54  $multi = new CurlMulti();
55  $request1 = new Request('GET', 'http://www.google.com/');
56  $multi->add($request1);
57  $this->assertEquals(array($request1), $multi->all());
58  $request2 = new Request('POST', 'http://www.google.com/');
59  $multi->add($request2);
60  $this->assertEquals(array($request1, $request2), $multi->all());
61  $this->assertEquals(2, count($multi));
62  }
63 
64  public function testRequestsCanBeRemoved()
65  {
66  $request1 = new Request('GET', 'http://www.google.com/');
67  $this->multi->add($request1);
68  $request2 = new Request('PUT', 'http://www.google.com/');
69  $this->multi->add($request2);
70  $this->assertEquals(array($request1, $request2), $this->multi->all());
71  $this->assertTrue($this->multi->remove($request1));
72  $this->assertFalse($this->multi->remove($request1));
73  $this->assertEquals(array($request2), $this->multi->all());
74  }
75 
77  {
78  $this->multi->add(new Request('GET', 'http://www.google.com/'));
79  $this->multi->reset();
80  $this->assertEquals(array(), $this->multi->all());
81  }
82 
83  public function testSendsRequestsThroughCurl()
84  {
85  $this->getServer()->enqueue(array(
86  "HTTP/1.1 204 No content\r\n" .
87  "Content-Length: 0\r\n" .
88  "Server: Jetty(6.1.3)\r\n\r\n",
89  "HTTP/1.1 200 OK\r\n" .
90  "Content-Type: text/html; charset=utf-8\r\n" .
91  "Content-Length: 4\r\n" .
92  "Server: Jetty(6.1.3)\r\n\r\n" .
93  "data"
94  ));
95 
96  $request1 = new Request('GET', $this->getServer()->getUrl());
97  $request2 = new Request('GET', $this->getServer()->getUrl());
98  $this->multi->add($request1);
99  $this->multi->add($request2);
100  $this->multi->send();
101 
102  $response1 = $request1->getResponse();
103  $response2 = $request2->getResponse();
104  $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response1);
105  $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response2);
106 
107  $this->assertTrue($response1->getBody(true) == 'data' || $response2->getBody(true) == 'data');
108  $this->assertTrue($response1->getBody(true) == '' || $response2->getBody(true) == '');
109  $this->assertTrue($response1->getStatusCode() == '204' || $response2->getStatusCode() == '204');
110  $this->assertNotEquals((string) $response1, (string) $response2);
111  }
112 
114  {
115  $this->getServer()->enqueue(array(
116  "HTTP/1.1 200 OK\r\n" .
117  "Content-Type: text/html; charset=utf-8\r\n" .
118  "Content-Length: 4\r\n" .
119  "Server: Jetty(6.1.3)\r\n" .
120  "\r\n" .
121  "data",
122  "HTTP/1.1 204 No content\r\n" .
123  "Content-Length: 0\r\n" .
124  "Server: Jetty(6.1.3)\r\n" .
125  "\r\n",
126  "HTTP/1.1 404 Not Found\r\n" .
127  "Content-Length: 0\r\n" .
128  "\r\n"
129  ));
130 
131  $request1 = new Request('GET', $this->getServer()->getUrl());
132  $request2 = new Request('HEAD', $this->getServer()->getUrl());
133  $request3 = new Request('GET', $this->getServer()->getUrl());
134  $this->multi->add($request1);
135  $this->multi->add($request2);
136  $this->multi->add($request3);
137 
138  try {
139  $this->multi->send();
140  $this->fail('MultiTransferException not thrown when aggregating request exceptions');
141  } catch (MultiTransferException $e) {
142 
143  $this->assertTrue($e->containsRequest($request1));
144  $this->assertTrue($e->containsRequest($request2));
145  $this->assertTrue($e->containsRequest($request3));
146  $this->assertInstanceOf('ArrayIterator', $e->getIterator());
147  $this->assertEquals(1, count($e));
148  $exceptions = $e->getIterator();
149 
150  $response1 = $request1->getResponse();
151  $response2 = $request2->getResponse();
152  $response3 = $request3->getResponse();
153 
154  $this->assertNotEquals((string) $response1, (string) $response2);
155  $this->assertNotEquals((string) $response3, (string) $response1);
156  $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response1);
157  $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response2);
158  $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response3);
159 
160  $failed = $exceptions[0]->getResponse();
161  $this->assertEquals(404, $failed->getStatusCode());
162  $this->assertEquals(1, count($e));
163 
164  // Test the IteratorAggregate functionality
165  foreach ($e as $except) {
166  $this->assertEquals($failed, $except->getResponse());
167  }
168 
169  $this->assertEquals(1, count($e->getFailedRequests()));
170  $this->assertEquals(2, count($e->getSuccessfulRequests()));
171  $this->assertEquals(3, count($e->getAllRequests()));
172  }
173  }
174 
175  public function testCurlErrorsAreCaught()
176  {
177  $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
178  try {
179  $request = RequestFactory::getInstance()->create('GET', 'http://127.0.0.1:9876/');
180  $request->setClient(new Client());
181  $request->getCurlOptions()->set(CURLOPT_FRESH_CONNECT, true);
182  $request->getCurlOptions()->set(CURLOPT_FORBID_REUSE, true);
183  $request->getCurlOptions()->set(CURLOPT_CONNECTTIMEOUT_MS, 5);
184  $request->send();
185  $this->fail('CurlException not thrown');
186  } catch (CurlException $e) {
187  $m = $e->getMessage();
188  $this->assertContains('[curl] ', $m);
189  $this->assertContains('[url] http://127.0.0.1:9876/', $m);
190  $this->assertInternalType('array', $e->getCurlInfo());
191  }
192  }
193 
194  public function testRemovesQueuedRequests()
195  {
196  $request = RequestFactory::getInstance()->create('GET', 'http://127.0.0.1:9876/');
197  $r = new Response(200);
198  $request->setClient(new Client());
199  $request->setResponse($r, true);
200  $this->multi->add($request);
201  $this->multi->send();
202  $this->assertSame($r, $request->getResponse());
203  }
204 
206  {
207  $this->getServer()->flush();
208  $this->getServer()->enqueue(array("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"));
209  $client = new Client($this->getServer()->getUrl());
210  $r = $client->get();
211  $r->getEventDispatcher()->addListener('request.receive.status_line', function (Event $event) use ($client) {
212  // Create a request using a queued response
213  $request = $client->get()->setResponse(new Response(200), true);
214  $request->send();
215  });
216  $r->send();
217  $this->assertEquals(1, count($this->getServer()->getReceivedRequests(false)));
218  }
219 
221  {
222  $client = new Client($this->getServer()->getUrl());
223  $multi = new CurlMulti();
224  $client->setCurlMulti($multi);
225  $request = $client->get();
226  $request->getEventDispatcher()->addListener('request.before_send', function() {
227  throw new \RuntimeException('Testing!');
228  });
229  try {
230  $request->send();
231  $this->fail('Did not throw');
232  } catch (\RuntimeException $e) {
233  // Ensure it was removed
234  $this->assertEquals(0, count($multi));
235  }
236  }
237 
243  {
244  $client = new Client($this->getServer()->getUrl());
245  $request = $client->get();
246  $request->getEventDispatcher()->addListener('request.before_send', function() {
247  throw new \RuntimeException('Thrown before sending!');
248  });
249  $client->send(array($request));
250  }
251 
253  {
254  $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
255  $client = new Client($this->getServer()->getUrl());
256  $r = $client->get();
257  $r->getEventDispatcher()->addListener('request.sent', function() use ($client) {
258  // Create a request using a queued response
259  $client->get()->setResponse(new Response(404), true)->send();
260  });
261  try {
262  $r->send();
263  $this->fail('Did not throw');
264  } catch (BadResponseException $e) {
265  $this->assertCount(0, $client->getCurlMulti());
266  }
267  }
268 
270  {
271  $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
272  $client = new Client($this->getServer()->getUrl());
273  $r = $client->get();
274  $r->getEventDispatcher()->addListener('request.before_send', function() use ($client) {
275  // Create a request using a queued response
276  $client->get()->setResponse(new Response(404), true)->send();
277  });
278  try {
279  $r->send();
280  $this->fail('Did not throw');
281  } catch (BadResponseException $e) {
282  $this->assertCount(0, $client->getCurlMulti());
283  }
284  }
285 
291  {
292  $client = new Client($this->getServer()->getUrl());
293  $multi = $this->getMock('Guzzle\\Http\\Curl\\CurlMulti', array('perform'));
294  $multi->expects($this->once())
295  ->method('perform')
296  ->will($this->throwException(new \RuntimeException('test')));
297  $multi->add($client->get());
298  $multi->send();
299  }
300 
302  {
303  if (!defined('CURLOPT_TIMEOUT_MS')) {
304  $this->markTestSkipped('Update curl');
305  }
306 
307  // Create a client that is bound to fail connecting
308  $client = new Client('http://127.0.0.1:123', array(
309  'curl.CURLOPT_PORT' => 123,
310  'curl.CURLOPT_CONNECTTIMEOUT_MS' => 1,
311  ));
312 
313  $request = $client->get();
314  $multi = new CurlMulti();
315  $multi->add($request);
316 
317  // Listen for request exceptions, and when they occur, first change the
318  // state of the request back to transferring, and then just allow it to
319  // exception out
320  $request->getEventDispatcher()->addListener('request.exception', function(Event $event) use ($multi) {
321  $retries = $event['request']->getParams()->get('retries');
322  // Allow the first failure to retry
323  if ($retries == 0) {
324  $event['request']->setState('transfer');
325  $event['request']->getParams()->set('retries', 1);
326  // Remove the request to try again
327  $multi->remove($event['request']);
328  $multi->add($event['request']);
329  }
330  });
331 
332  try {
333  $multi->send();
334  $this->fail('Did not throw an exception at all!?!');
335  } catch (\Exception $e) {
336  $this->assertEquals(1, $request->getParams()->get('retries'));
337  }
338  }
339 
341  {
342  $this->getServer()->flush();
343  $client = new Client($this->getServer()->getUrl());
344  $request = $client->get();
345  $request->getEventDispatcher()->addListener('request.before_send', function(Event $event) {
346  $event['request']->setResponse(new Response(200));
347  });
348 
349  $multi = new CurlMulti();
350  $multi->add($request);
351  $multi->send();
352  $this->assertEquals(0, count($this->getServer()->getReceivedRequests(false)));
353  }
354 
356  {
357  // Attempt a port that 99.9% is not listening
358  $client = new Client('http://127.0.0.1:123');
359  $request = $client->get();
360  // Ensure it times out quickly if needed
361  $request->getCurlOptions()->set(CURLOPT_TIMEOUT_MS, 1)->set(CURLOPT_CONNECTTIMEOUT_MS, 1);
362 
363  $request->getEventDispatcher()->addListener('request.exception', function(Event $event) use (&$count) {
364  $event['request']->setResponse(new Response(200));
365  });
366 
367  $multi = new CurlMulti();
368  $multi->add($request);
369  $multi->send();
370 
371  // Ensure that the exception was caught, and the response was set manually
372  $this->assertEquals(200, $request->getResponse()->getStatusCode());
373  }
374 
375  public function testHardResetReopensMultiHandle()
376  {
377  $this->getServer()->enqueue(array(
378  "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
379  "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
380  ));
381 
382  $stream = fopen('php://temp', 'w+');
383  $client = new Client($this->getServer()->getUrl());
384  $client->getConfig()->set('curl.CURLOPT_VERBOSE', true)->set('curl.CURLOPT_STDERR', $stream);
385 
386  $request = $client->get();
387  $multi = new CurlMulti();
388  $multi->add($request);
389  $multi->send();
390  $multi->reset(true);
391  $multi->add($request);
392  $multi->send();
393 
394  rewind($stream);
395  $this->assertNotContains('Re-using existing connection', stream_get_contents($stream));
396  }
397 
399  {
400  $multi = new CurlMulti();
401 
402  // Set the state of the multi object to sending to trigger the exception
403  $reflector = new \ReflectionMethod('Guzzle\Http\Curl\CurlMulti', 'checkCurlResult');
404  $reflector->setAccessible(true);
405 
406  // Successful
407  $reflector->invoke($multi, 0);
408 
409  // Known error
410  try {
411  $reflector->invoke($multi, CURLM_BAD_HANDLE);
412  $this->fail('Expected an exception here');
413  } catch (CurlException $e) {
414  $this->assertContains('The passed-in handle is not a valid CURLM handle.', $e->getMessage());
415  $this->assertContains('CURLM_BAD_HANDLE', $e->getMessage());
416  $this->assertContains(strval(CURLM_BAD_HANDLE), $e->getMessage());
417  }
418 
419  // Unknown error
420  try {
421  $reflector->invoke($multi, 255);
422  $this->fail('Expected an exception here');
423  } catch (CurlException $e) {
424  $this->assertEquals('Unexpected cURL error: 255', $e->getMessage());
425  }
426  }
427 
429  {
430  $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
431  $request = new Request('PUT', $this->getServer()->getUrl());
432  $that = $this;
433  $request->getEventDispatcher()->addListener('request.before_send', function ($event) use ($that) {
434  $that->assertEquals(0, $event['request']->getHeader('Content-Length'));
435  });
436  $this->multi->add($request);
437  $this->multi->send();
438  }
439 
441  {
442  $this->getServer()->flush();
443  $this->getServer()->enqueue(array(
444  "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest",
445  "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
446  ));
447  $client = new Client($this->getServer()->getUrl());
448  $request = $client->put('/', null, fopen($this->getServer()->getUrl(), 'r'));
449  $request->setHeader('Content-Length', 4);
450  $request->send();
451  $received = $this->getServer()->getReceivedRequests(true);
452  $this->assertFalse($received[1]->hasHeader('Transfer-Encoding'));
453  $this->assertEquals(4, (string) $received[1]->getHeader('Content-Length'));
454  }
455 }
Guzzle\Tests\Http\Curl\CurlMultiTest\testCatchesExceptionsWhenRemovingQueuedRequestsBeforeSending
testCatchesExceptionsWhenRemovingQueuedRequestsBeforeSending()
Definition: CurlMultiTest.php:272
Guzzle\Http\Exception\CurlException
Definition: CurlException.php:10
Guzzle\Http\Exception\MultiTransferException\getFailedRequests
getFailedRequests()
Definition: MultiTransferException.php:129
Guzzle\Tests\Http\Curl\CurlMultiTest\testThrowsMeaningfulExceptionsForCurlMultiErrors
testThrowsMeaningfulExceptionsForCurlMultiErrors()
Definition: CurlMultiTest.php:401
Guzzle\Tests\Http\Curl\CurlMultiTest\testDestructorClosesMultiHandle
testDestructorClosesMultiHandle()
Definition: CurlMultiTest.php:48
Guzzle\Tests\GuzzleTestCase
Definition: GuzzleTestCase.php:22
Guzzle\Tests\Http\Curl\CurlMultiTest\testCatchesExceptionsBeforeSendingSingleRequest
testCatchesExceptionsBeforeSendingSingleRequest()
Definition: CurlMultiTest.php:223
Guzzle\Tests\Http\Curl\CurlMultiTest\testHardResetReopensMultiHandle
testHardResetReopensMultiHandle()
Definition: CurlMultiTest.php:378
Guzzle\Tests\Http\Curl\CurlMultiTest\testSendsThroughCurlAndAggregatesRequestExceptions
testSendsThroughCurlAndAggregatesRequestExceptions()
Definition: CurlMultiTest.php:116
Guzzle\Tests\Http\Curl\CurlMultiTest\testRemovesQueuedRequests
testRemovesQueuedRequests()
Definition: CurlMultiTest.php:197
Guzzle\Http\Message\Response
Definition: paymethod/paypal/lib/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Response.php:17
Guzzle\Tests\Http\Curl\CurlMultiTest\testsResetRemovesRequestsAndResetsState
testsResetRemovesRequestsAndResetsState()
Definition: CurlMultiTest.php:79
Guzzle\Common\Exception\ExceptionCollection\getIterator
getIterator()
Definition: ExceptionCollection.php:79
Guzzle\Tests\Http\Curl
Definition: CurlHandleTest.php:3
Guzzle\Http\Exception\MultiTransferException
Definition: MultiTransferException.php:11
Guzzle\Http\Exception\MultiTransferException\getAllRequests
getAllRequests()
Definition: MultiTransferException.php:22
Guzzle\Tests\Http\Curl\CurlMultiTest\testRequestsCanBeRemoved
testRequestsCanBeRemoved()
Definition: CurlMultiTest.php:67
Guzzle\Tests\Http\Curl\CurlMultiTest\tearDown
tearDown()
Definition: CurlMultiTest.php:37
Guzzle\Tests\Http\Curl\CurlMultiTest\testSendsRequestsThroughCurl
testSendsRequestsThroughCurl()
Definition: CurlMultiTest.php:86
Guzzle\Tests\Http\Curl\CurlMultiTest\testCatchesExceptionsWhenRemovingQueuedRequests
testCatchesExceptionsWhenRemovingQueuedRequests()
Definition: CurlMultiTest.php:255
Guzzle\Tests\Http\Curl\CurlMultiTest\testRemovesQueuedRequestsAddedInTransit
testRemovesQueuedRequestsAddedInTransit()
Definition: CurlMultiTest.php:208
Guzzle\Common\Event
Definition: lib/vendor/guzzle/guzzle/src/Guzzle/Common/Event.php:10
Guzzle\Tests\Http\Curl\CurlMultiTest
Definition: CurlMultiTest.php:20
Guzzle\Tests\Http\Curl\CurlMultiTest\testConstructorCreateMultiHandle
testConstructorCreateMultiHandle()
Definition: CurlMultiTest.php:42
Guzzle\Tests\Http\Curl\CurlMultiTest\testCurlErrorsAreCaught
testCurlErrorsAreCaught()
Definition: CurlMultiTest.php:178
Guzzle\Http\Message\Request
Definition: paymethod/paypal/lib/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php:25
Guzzle\Tests\Http\Curl\CurlMultiTest\testDoesNotSendRequestsDecliningToBeSent
testDoesNotSendRequestsDecliningToBeSent()
Definition: CurlMultiTest.php:304
Guzzle\Tests\Http\Curl\CurlMultiTest\testDoesNotThrowExceptionsWhenRequestsRecoverWithRetry
testDoesNotThrowExceptionsWhenRequestsRecoverWithRetry()
Definition: CurlMultiTest.php:343
Guzzle\Tests\Http\Curl\CurlMultiTest\testDoesNotThrowExceptionsWhenRequestsRecoverWithSuccess
testDoesNotThrowExceptionsWhenRequestsRecoverWithSuccess()
Definition: CurlMultiTest.php:358
Guzzle\Http\Message\RequestFactory
Definition: lib/vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactory.php:14
Guzzle\Tests\Http\Curl\CurlMultiTest\testRequestsCanBeAddedAndCounted
testRequestsCanBeAddedAndCounted()
Definition: CurlMultiTest.php:55
Guzzle\Tests\Http\Curl\CurlMultiTest\setUp
setUp()
Definition: CurlMultiTest.php:31
Guzzle\Tests\Mock\MockMulti
Definition: MockMulti.php:5
Guzzle\Http\Client
Definition: paymethod/paypal/lib/vendor/guzzle/guzzle/src/Guzzle/Http/Client.php:24
Guzzle\Http\Curl\CurlMulti
Definition: CurlMulti.php:16
Guzzle\Http\Exception\BadResponseException
Definition: lib/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/BadResponseException.php:11
Guzzle\Http\Message\RequestFactory\getInstance
static getInstance()
Definition: lib/vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactory.php:42
Guzzle\Tests\Http\Curl\CurlMultiTest\testRequestBeforeSendIncludesContentLengthHeaderIfEmptyBody
testRequestBeforeSendIncludesContentLengthHeaderIfEmptyBody()
Definition: CurlMultiTest.php:431
Guzzle\Tests\Http\Curl\CurlMultiTest\testRemovesConflictingTransferEncodingHeader
testRemovesConflictingTransferEncodingHeader()
Definition: CurlMultiTest.php:443
Guzzle\Http\Exception\MultiTransferException\getSuccessfulRequests
getSuccessfulRequests()
Definition: MultiTransferException.php:119
Guzzle\Tests\Http\Curl\CurlMultiTest\testCatchesExceptionsBeforeSendingMultipleRequests
testCatchesExceptionsBeforeSendingMultipleRequests()
Definition: CurlMultiTest.php:245
Guzzle\Common\Exception\RuntimeException
Definition: lib/vendor/guzzle/guzzle/src/Guzzle/Common/Exception/RuntimeException.php:5
Guzzle\Tests\GuzzleTestCase\getServer
static getServer()
Definition: GuzzleTestCase.php:36
Guzzle\Http\Exception\MultiTransferException\containsRequest
containsRequest(RequestInterface $request)
Definition: MultiTransferException.php:141
Guzzle\Tests\Http\Curl\CurlMultiTest\testDoesNotCatchRandomExceptionsThrownDuringPerform
testDoesNotCatchRandomExceptionsThrownDuringPerform()
Definition: CurlMultiTest.php:293
Guzzle\Http\Exception\CurlException\getCurlInfo
getCurlInfo()
Definition: CurlException.php:82