ClientTest.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * Redistributions of files must retain the above copyright notice.
  8. *
  9. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  10. * @link https://cakephp.org CakePHP(tm) Project
  11. * @since 3.0.0
  12. * @license https://opensource.org/licenses/mit-license.php MIT License
  13. */
  14. namespace Cake\Test\TestCase\Http;
  15. use Cake\Http\Client;
  16. use Cake\Http\Client\Request;
  17. use Cake\Http\Client\Response;
  18. use Cake\Http\Cookie\Cookie;
  19. use Cake\Http\Cookie\CookieCollection;
  20. use Cake\TestSuite\TestCase;
  21. /**
  22. * HTTP client test.
  23. */
  24. class ClientTest extends TestCase
  25. {
  26. /**
  27. * Test storing config options and modifying them.
  28. *
  29. * @return void
  30. */
  31. public function testConstructConfig()
  32. {
  33. $config = [
  34. 'scheme' => 'http',
  35. 'host' => 'example.org',
  36. ];
  37. $http = new Client($config);
  38. $result = $http->config();
  39. foreach ($config as $key => $val) {
  40. $this->assertEquals($val, $result[$key]);
  41. }
  42. $result = $http->config([
  43. 'auth' => ['username' => 'mark', 'password' => 'secret']
  44. ]);
  45. $this->assertSame($result, $http);
  46. $result = $http->config();
  47. $expected = [
  48. 'scheme' => 'http',
  49. 'host' => 'example.org',
  50. 'auth' => ['username' => 'mark', 'password' => 'secret']
  51. ];
  52. foreach ($expected as $key => $val) {
  53. $this->assertEquals($val, $result[$key]);
  54. }
  55. }
  56. /**
  57. * Data provider for buildUrl() tests
  58. *
  59. * @return array
  60. */
  61. public static function urlProvider()
  62. {
  63. return [
  64. [
  65. 'http://example.com/test.html',
  66. 'http://example.com/test.html',
  67. [],
  68. null,
  69. 'Null options'
  70. ],
  71. [
  72. 'http://example.com/test.html',
  73. 'http://example.com/test.html',
  74. [],
  75. [],
  76. 'Simple string'
  77. ],
  78. [
  79. 'http://example.com/test.html',
  80. '/test.html',
  81. [],
  82. ['host' => 'example.com'],
  83. 'host name option',
  84. ],
  85. [
  86. 'https://example.com/test.html',
  87. '/test.html',
  88. [],
  89. ['host' => 'example.com', 'scheme' => 'https'],
  90. 'HTTPS',
  91. ],
  92. [
  93. 'http://example.com:8080/test.html',
  94. '/test.html',
  95. [],
  96. ['host' => 'example.com', 'port' => '8080'],
  97. 'Non standard port',
  98. ],
  99. [
  100. 'http://example.com/test.html',
  101. '/test.html',
  102. [],
  103. ['host' => 'example.com', 'port' => '80'],
  104. 'standard port, does not display'
  105. ],
  106. [
  107. 'https://example.com/test.html',
  108. '/test.html',
  109. [],
  110. ['host' => 'example.com', 'scheme' => 'https', 'port' => '443'],
  111. 'standard port, does not display'
  112. ],
  113. [
  114. 'http://example.com/test.html',
  115. 'http://example.com/test.html',
  116. [],
  117. ['host' => 'example.com', 'scheme' => 'https'],
  118. 'options do not duplicate'
  119. ],
  120. [
  121. 'http://example.com/search?q=hi+there&cat%5Bid%5D%5B0%5D=2&cat%5Bid%5D%5B1%5D=3',
  122. 'http://example.com/search',
  123. ['q' => 'hi there', 'cat' => ['id' => [2, 3]]],
  124. [],
  125. 'query string data.'
  126. ],
  127. [
  128. 'http://example.com/search?q=hi+there&id=12',
  129. 'http://example.com/search?q=hi+there',
  130. ['id' => '12'],
  131. [],
  132. 'query string data with some already on the url.'
  133. ],
  134. [
  135. 'http://example.com/test.html',
  136. '//example.com/test.html',
  137. [],
  138. [
  139. 'scheme' => 'http'
  140. ],
  141. 'url without a scheme',
  142. ],
  143. ];
  144. }
  145. /**
  146. * @dataProvider urlProvider
  147. */
  148. public function testBuildUrl($expected, $url, $query, $opts)
  149. {
  150. $http = new Client();
  151. $result = $http->buildUrl($url, $query, $opts);
  152. $this->assertEquals($expected, $result);
  153. }
  154. /**
  155. * test simple get request with headers & cookies.
  156. *
  157. * @return void
  158. */
  159. public function testGetSimpleWithHeadersAndCookies()
  160. {
  161. $response = new Response();
  162. $headers = [
  163. 'User-Agent' => 'Cake',
  164. 'Connection' => 'close',
  165. 'Content-Type' => 'application/x-www-form-urlencoded',
  166. ];
  167. $cookies = [
  168. 'split' => 'value'
  169. ];
  170. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  171. ->setMethods(['send'])
  172. ->getMock();
  173. $mock->expects($this->once())
  174. ->method('send')
  175. ->with($this->callback(function ($request) use ($cookies, $headers) {
  176. $this->assertInstanceOf('Cake\Http\Client\Request', $request);
  177. $this->assertEquals(Request::METHOD_GET, $request->getMethod());
  178. $this->assertEquals('http://cakephp.org/test.html', $request->getUri() . '');
  179. $this->assertEquals('split=value', $request->getHeaderLine('Cookie'));
  180. $this->assertEquals($headers['Content-Type'], $request->getHeaderLine('content-type'));
  181. $this->assertEquals($headers['Connection'], $request->getHeaderLine('connection'));
  182. return true;
  183. }))
  184. ->will($this->returnValue([$response]));
  185. $http = new Client(['adapter' => $mock]);
  186. $result = $http->get('http://cakephp.org/test.html', [], [
  187. 'headers' => $headers,
  188. 'cookies' => $cookies,
  189. ]);
  190. $this->assertSame($result, $response);
  191. }
  192. /**
  193. * test get request with no data
  194. *
  195. * @return void
  196. */
  197. public function testGetNoData()
  198. {
  199. $response = new Response();
  200. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  201. ->setMethods(['send'])
  202. ->getMock();
  203. $mock->expects($this->once())
  204. ->method('send')
  205. ->with($this->callback(function ($request) {
  206. $this->assertEquals(Request::METHOD_GET, $request->getMethod());
  207. $this->assertEmpty($request->getHeaderLine('Content-Type'), 'Should have no content-type set');
  208. $this->assertEquals(
  209. 'http://cakephp.org/search',
  210. $request->getUri() . ''
  211. );
  212. return true;
  213. }))
  214. ->will($this->returnValue([$response]));
  215. $http = new Client([
  216. 'host' => 'cakephp.org',
  217. 'adapter' => $mock
  218. ]);
  219. $result = $http->get('/search');
  220. $this->assertSame($result, $response);
  221. }
  222. /**
  223. * test get request with querystring data
  224. *
  225. * @return void
  226. */
  227. public function testGetQuerystring()
  228. {
  229. $response = new Response();
  230. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  231. ->setMethods(['send'])
  232. ->getMock();
  233. $mock->expects($this->once())
  234. ->method('send')
  235. ->with($this->callback(function ($request) {
  236. $this->assertEquals(Request::METHOD_GET, $request->getMethod());
  237. $this->assertEquals(
  238. 'http://cakephp.org/search?q=hi+there&Category%5Bid%5D%5B0%5D=2&Category%5Bid%5D%5B1%5D=3',
  239. $request->getUri() . ''
  240. );
  241. return true;
  242. }))
  243. ->will($this->returnValue([$response]));
  244. $http = new Client([
  245. 'host' => 'cakephp.org',
  246. 'adapter' => $mock
  247. ]);
  248. $result = $http->get('/search', [
  249. 'q' => 'hi there',
  250. 'Category' => ['id' => [2, 3]]
  251. ]);
  252. $this->assertSame($result, $response);
  253. }
  254. /**
  255. * test get request with string of query data.
  256. *
  257. * @return void
  258. */
  259. public function testGetQuerystringString()
  260. {
  261. $response = new Response();
  262. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  263. ->setMethods(['send'])
  264. ->getMock();
  265. $mock->expects($this->once())
  266. ->method('send')
  267. ->with($this->callback(function ($request) {
  268. $this->assertEquals(
  269. 'http://cakephp.org/search?q=hi+there&Category%5Bid%5D%5B0%5D=2&Category%5Bid%5D%5B1%5D=3',
  270. $request->getUri() . ''
  271. );
  272. return true;
  273. }))
  274. ->will($this->returnValue([$response]));
  275. $http = new Client([
  276. 'host' => 'cakephp.org',
  277. 'adapter' => $mock
  278. ]);
  279. $data = [
  280. 'q' => 'hi there',
  281. 'Category' => ['id' => [2, 3]]
  282. ];
  283. $result = $http->get('/search', http_build_query($data));
  284. $this->assertSame($response, $result);
  285. }
  286. /**
  287. * Test a GET with a request body. Services like
  288. * elasticsearch use this feature.
  289. *
  290. * @return void
  291. */
  292. public function testGetWithContent()
  293. {
  294. $response = new Response();
  295. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  296. ->setMethods(['send'])
  297. ->getMock();
  298. $mock->expects($this->once())
  299. ->method('send')
  300. ->with($this->callback(function ($request) {
  301. $this->assertEquals(Request::METHOD_GET, $request->getMethod());
  302. $this->assertEquals('http://cakephp.org/search', '' . $request->getUri());
  303. $this->assertEquals('some data', '' . $request->getBody());
  304. return true;
  305. }))
  306. ->will($this->returnValue([$response]));
  307. $http = new Client([
  308. 'host' => 'cakephp.org',
  309. 'adapter' => $mock
  310. ]);
  311. $result = $http->get('/search', [
  312. '_content' => 'some data'
  313. ]);
  314. $this->assertSame($result, $response);
  315. }
  316. /**
  317. * Test invalid authentication types throw exceptions.
  318. *
  319. * @expectedException \Cake\Core\Exception\Exception
  320. * @return void
  321. */
  322. public function testInvalidAuthenticationType()
  323. {
  324. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  325. ->setMethods(['send'])
  326. ->getMock();
  327. $mock->expects($this->never())
  328. ->method('send');
  329. $http = new Client([
  330. 'host' => 'cakephp.org',
  331. 'adapter' => $mock
  332. ]);
  333. $result = $http->get('/', [], [
  334. 'auth' => ['type' => 'horribly broken']
  335. ]);
  336. }
  337. /**
  338. * Test setting basic authentication with get
  339. *
  340. * @return void
  341. */
  342. public function testGetWithAuthenticationAndProxy()
  343. {
  344. $response = new Response();
  345. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  346. ->setMethods(['send'])
  347. ->getMock();
  348. $headers = [
  349. 'Authorization' => 'Basic ' . base64_encode('mark:secret'),
  350. 'Proxy-Authorization' => 'Basic ' . base64_encode('mark:pass'),
  351. ];
  352. $mock->expects($this->once())
  353. ->method('send')
  354. ->with($this->callback(function ($request) use ($headers) {
  355. $this->assertEquals(Request::METHOD_GET, $request->getMethod());
  356. $this->assertEquals('http://cakephp.org/', '' . $request->getUri());
  357. $this->assertEquals($headers['Authorization'], $request->getHeaderLine('Authorization'));
  358. $this->assertEquals($headers['Proxy-Authorization'], $request->getHeaderLine('Proxy-Authorization'));
  359. return true;
  360. }))
  361. ->will($this->returnValue([$response]));
  362. $http = new Client([
  363. 'host' => 'cakephp.org',
  364. 'adapter' => $mock
  365. ]);
  366. $result = $http->get('/', [], [
  367. 'auth' => ['username' => 'mark', 'password' => 'secret'],
  368. 'proxy' => ['username' => 'mark', 'password' => 'pass'],
  369. ]);
  370. $this->assertSame($result, $response);
  371. }
  372. /**
  373. * Test authentication adapter that mutates request.
  374. *
  375. * @return void
  376. */
  377. public function testAuthenticationWithMutation()
  378. {
  379. static::setAppNamespace();
  380. $response = new Response();
  381. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  382. ->setMethods(['send'])
  383. ->getMock();
  384. $headers = [
  385. 'Authorization' => 'Bearer abc123',
  386. 'Proxy-Authorization' => 'Bearer abc123',
  387. ];
  388. $mock->expects($this->once())
  389. ->method('send')
  390. ->with($this->callback(function ($request) use ($headers) {
  391. $this->assertEquals(Request::METHOD_GET, $request->getMethod());
  392. $this->assertEquals('http://cakephp.org/', '' . $request->getUri());
  393. $this->assertEquals($headers['Authorization'], $request->getHeaderLine('Authorization'));
  394. $this->assertEquals($headers['Proxy-Authorization'], $request->getHeaderLine('Proxy-Authorization'));
  395. return true;
  396. }))
  397. ->will($this->returnValue([$response]));
  398. $http = new Client([
  399. 'host' => 'cakephp.org',
  400. 'adapter' => $mock
  401. ]);
  402. $result = $http->get('/', [], [
  403. 'auth' => ['type' => 'TestApp\Http\CompatAuth'],
  404. 'proxy' => ['type' => 'TestApp\Http\CompatAuth'],
  405. ]);
  406. $this->assertSame($result, $response);
  407. }
  408. /**
  409. * Return a list of HTTP methods.
  410. *
  411. * @return array
  412. */
  413. public static function methodProvider()
  414. {
  415. return [
  416. [Request::METHOD_GET],
  417. [Request::METHOD_POST],
  418. [Request::METHOD_PUT],
  419. [Request::METHOD_DELETE],
  420. [Request::METHOD_PATCH],
  421. [Request::METHOD_OPTIONS],
  422. [Request::METHOD_TRACE],
  423. ];
  424. }
  425. /**
  426. * test simple POST request.
  427. *
  428. * @dataProvider methodProvider
  429. * @return void
  430. */
  431. public function testMethodsSimple($method)
  432. {
  433. $response = new Response();
  434. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  435. ->setMethods(['send'])
  436. ->getMock();
  437. $mock->expects($this->once())
  438. ->method('send')
  439. ->with($this->callback(function ($request) use ($method) {
  440. $this->assertInstanceOf('Cake\Http\Client\Request', $request);
  441. $this->assertEquals($method, $request->getMethod());
  442. $this->assertEquals('http://cakephp.org/projects/add', '' . $request->getUri());
  443. return true;
  444. }))
  445. ->will($this->returnValue([$response]));
  446. $http = new Client([
  447. 'host' => 'cakephp.org',
  448. 'adapter' => $mock
  449. ]);
  450. $result = $http->{$method}('/projects/add');
  451. $this->assertSame($result, $response);
  452. }
  453. /**
  454. * Provider for testing the type option.
  455. *
  456. * @return array
  457. */
  458. public static function typeProvider()
  459. {
  460. return [
  461. ['application/json', 'application/json'],
  462. ['json', 'application/json'],
  463. ['xml', 'application/xml'],
  464. ['application/xml', 'application/xml'],
  465. ];
  466. }
  467. /**
  468. * Test that using the 'type' option sets the correct headers
  469. *
  470. * @dataProvider typeProvider
  471. * @return void
  472. */
  473. public function testPostWithTypeKey($type, $mime)
  474. {
  475. $response = new Response();
  476. $data = 'some data';
  477. $headers = [
  478. 'Content-Type' => $mime,
  479. 'Accept' => $mime,
  480. ];
  481. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  482. ->setMethods(['send'])
  483. ->getMock();
  484. $mock->expects($this->once())
  485. ->method('send')
  486. ->with($this->callback(function ($request) use ($headers) {
  487. $this->assertEquals(Request::METHOD_POST, $request->getMethod());
  488. $this->assertEquals($headers['Content-Type'], $request->getHeaderLine('Content-Type'));
  489. $this->assertEquals($headers['Accept'], $request->getHeaderLine('Accept'));
  490. return true;
  491. }))
  492. ->will($this->returnValue([$response]));
  493. $http = new Client([
  494. 'host' => 'cakephp.org',
  495. 'adapter' => $mock
  496. ]);
  497. $http->post('/projects/add', $data, ['type' => $type]);
  498. }
  499. /**
  500. * Test that string payloads with no content type have a default content-type set.
  501. *
  502. * @return void
  503. */
  504. public function testPostWithStringDataDefaultsToFormEncoding()
  505. {
  506. $response = new Response();
  507. $data = 'some=value&more=data';
  508. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  509. ->setMethods(['send'])
  510. ->getMock();
  511. $mock->expects($this->any())
  512. ->method('send')
  513. ->with($this->callback(function ($request) use ($data) {
  514. $this->assertEquals($data, '' . $request->getBody());
  515. $this->assertEquals('application/x-www-form-urlencoded', $request->getHeaderLine('content-type'));
  516. return true;
  517. }))
  518. ->will($this->returnValue([$response]));
  519. $http = new Client([
  520. 'host' => 'cakephp.org',
  521. 'adapter' => $mock
  522. ]);
  523. $http->post('/projects/add', $data);
  524. $http->put('/projects/add', $data);
  525. $http->delete('/projects/add', $data);
  526. }
  527. /**
  528. * Test that exceptions are raised on invalid types.
  529. *
  530. * @expectedException \Cake\Core\Exception\Exception
  531. * @return void
  532. */
  533. public function testExceptionOnUnknownType()
  534. {
  535. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  536. ->setMethods(['send'])
  537. ->getMock();
  538. $mock->expects($this->never())
  539. ->method('send');
  540. $http = new Client([
  541. 'host' => 'cakephp.org',
  542. 'adapter' => $mock
  543. ]);
  544. $http->post('/projects/add', 'it works', ['type' => 'invalid']);
  545. }
  546. /**
  547. * Test that Client stores cookies
  548. *
  549. * @return void
  550. */
  551. public function testCookieStorage()
  552. {
  553. $adapter = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  554. ->setMethods(['send'])
  555. ->getMock();
  556. $headers = [
  557. 'HTTP/1.0 200 Ok',
  558. 'Set-Cookie: first=1',
  559. 'Set-Cookie: expiring=now; Expires=Wed, 09-Jun-1999 10:18:14 GMT'
  560. ];
  561. $response = new Response($headers, '');
  562. $adapter->expects($this->at(0))
  563. ->method('send')
  564. ->will($this->returnValue([$response]));
  565. $http = new Client([
  566. 'host' => 'cakephp.org',
  567. 'adapter' => $adapter,
  568. ]);
  569. $http->get('/projects');
  570. $cookies = $http->cookies();
  571. $this->assertCount(1, $cookies);
  572. $this->assertTrue($cookies->has('first'));
  573. $this->assertFalse($cookies->has('expiring'));
  574. }
  575. /**
  576. * Test cookieJar config option.
  577. *
  578. * @return void
  579. */
  580. public function testCookieJar()
  581. {
  582. $jar = new CookieCollection();
  583. $http = new Client([
  584. 'cookieJar' => $jar
  585. ]);
  586. $this->assertSame($jar, $http->cookies());
  587. }
  588. /**
  589. * Test addCookie() method.
  590. *
  591. * @return void
  592. */
  593. public function testAddCookie()
  594. {
  595. $client = new Client();
  596. $cookie = new Cookie('foo');
  597. $this->assertFalse($client->cookies()->has('foo'));
  598. $client->addCookie($cookie);
  599. $this->assertTrue($client->cookies()->has('foo'));
  600. }
  601. /**
  602. * test head request with querystring data
  603. *
  604. * @return void
  605. */
  606. public function testHeadQuerystring()
  607. {
  608. $response = new Response();
  609. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  610. ->setMethods(['send'])
  611. ->getMock();
  612. $mock->expects($this->once())
  613. ->method('send')
  614. ->with($this->callback(function ($request) {
  615. $this->assertInstanceOf('Cake\Http\Client\Request', $request);
  616. $this->assertEquals(Request::METHOD_HEAD, $request->getMethod());
  617. $this->assertEquals('http://cakephp.org/search?q=hi+there', '' . $request->getUri());
  618. return true;
  619. }))
  620. ->will($this->returnValue([$response]));
  621. $http = new Client([
  622. 'host' => 'cakephp.org',
  623. 'adapter' => $mock
  624. ]);
  625. $result = $http->head('/search', [
  626. 'q' => 'hi there',
  627. ]);
  628. $this->assertSame($result, $response);
  629. }
  630. /**
  631. * test redirects
  632. *
  633. * @return void
  634. */
  635. public function testRedirects()
  636. {
  637. $url = 'http://cakephp.org';
  638. $adapter = $this->getMockBuilder(Client\Adapter\Stream::class)
  639. ->setMethods(['send'])
  640. ->getMock();
  641. $redirect = new Response([
  642. 'HTTP/1.0 301',
  643. 'Location: http://cakephp.org/redirect1?foo=bar',
  644. 'Set-Cookie: redirect1=true;path=/',
  645. ]);
  646. $adapter->expects($this->at(0))
  647. ->method('send')
  648. ->with(
  649. $this->callback(function ($request) use ($url) {
  650. $this->assertInstanceOf(Request::class, $request);
  651. $this->assertEquals($url, $request->getUri());
  652. return true;
  653. }),
  654. $this->callback(function ($options) {
  655. $this->assertArrayNotHasKey('redirect', $options);
  656. return true;
  657. })
  658. )
  659. ->willReturn([$redirect]);
  660. $redirect2 = new Response([
  661. 'HTTP/1.0 301',
  662. 'Location: /redirect2#foo',
  663. 'Set-Cookie: redirect2=true;path=/',
  664. ]);
  665. $adapter->expects($this->at(1))
  666. ->method('send')
  667. ->with(
  668. $this->callback(function ($request) use ($url) {
  669. $this->assertInstanceOf(Request::class, $request);
  670. $this->assertEquals($url . '/redirect1?foo=bar', $request->getUri());
  671. return true;
  672. }),
  673. $this->callback(function ($options) {
  674. $this->assertArrayNotHasKey('redirect', $options);
  675. return true;
  676. })
  677. )
  678. ->willReturn([$redirect2]);
  679. $response = new Response([
  680. 'HTTP/1.0 200'
  681. ]);
  682. $adapter->expects($this->at(2))
  683. ->method('send')
  684. ->with($this->callback(function ($request) use ($url) {
  685. $this->assertInstanceOf(Request::class, $request);
  686. $this->assertEquals($url . '/redirect2#foo', $request->getUri());
  687. return true;
  688. }))
  689. ->willReturn([$response]);
  690. $client = new Client([
  691. 'adapter' => $adapter
  692. ]);
  693. $result = $client->send(new Request($url), [
  694. 'redirect' => 10
  695. ]);
  696. $this->assertInstanceOf(Response::class, $result);
  697. $this->assertTrue($result->isOk());
  698. $cookies = $client->cookies()->get($url);
  699. $this->assertArrayHasKey('redirect1', $cookies);
  700. $this->assertArrayHasKey('redirect2', $cookies);
  701. }
  702. }