GuzzleClientTest.php 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  1. <?php
  2. namespace GuzzleHttp\Tests\Command\Guzzle;
  3. use GuzzleHttp\Client as HttpClient;
  4. use GuzzleHttp\Command\CommandInterface;
  5. use GuzzleHttp\Command\Guzzle\Description;
  6. use GuzzleHttp\Command\Guzzle\GuzzleClient;
  7. use GuzzleHttp\Command\Result;
  8. use GuzzleHttp\Command\ResultInterface;
  9. use GuzzleHttp\Handler\MockHandler;
  10. use GuzzleHttp\Psr7\Request;
  11. use GuzzleHttp\Psr7\Response;
  12. use Psr\Http\Message\RequestInterface;
  13. use Psr\Http\Message\ResponseInterface;
  14. /**
  15. * @covers \GuzzleHttp\Command\Guzzle\GuzzleClient
  16. */
  17. class GuzzleClientTest extends \PHPUnit_Framework_TestCase
  18. {
  19. public function testExecuteCommandViaMagicMethod()
  20. {
  21. $client = $this->getServiceClient(
  22. [
  23. new Response(200, [], '{"foo":"bar"}'),
  24. new Response(200, [], '{"foofoo":"barbar"}'),
  25. ],
  26. null,
  27. $this->commandToRequestTransformer()
  28. );
  29. // Synchronous
  30. $result1 = $client->doThatThingYouDo(['fizz' => 'buzz']);
  31. $this->assertEquals('bar', $result1['foo']);
  32. $this->assertEquals('buzz', $result1['_request']['fizz']);
  33. $this->assertEquals('doThatThingYouDo', $result1['_request']['action']);
  34. // Asynchronous
  35. $result2 = $client->doThatThingOtherYouDoAsync(['fizz' => 'buzz'])->wait();
  36. $this->assertEquals('barbar', $result2['foofoo']);
  37. $this->assertEquals('doThatThingOtherYouDo', $result2['_request']['action']);
  38. }
  39. public function testExecuteWithQueryLocation()
  40. {
  41. $mock = new MockHandler();
  42. $client = $this->getServiceClient(
  43. [
  44. new Response(200, [], '{"foo":"bar"}'),
  45. new Response(200, [], '{"foo":"bar"}')
  46. ],
  47. $mock
  48. );
  49. $client->doQueryLocation(['foo' => 'Foo']);
  50. $this->assertEquals('foo=Foo', $mock->getLastRequest()->getUri()->getQuery());
  51. $client->doQueryLocation([
  52. 'foo' => 'Foo',
  53. 'bar' => 'Bar',
  54. 'baz' => 'Baz'
  55. ]);
  56. $last = $mock->getLastRequest();
  57. $this->assertEquals('foo=Foo&bar=Bar&baz=Baz', $last->getUri()->getQuery());
  58. }
  59. public function testExecuteWithBodyLocation()
  60. {
  61. $mock = new MockHandler();
  62. $client = $this->getServiceClient(
  63. [
  64. new Response(200, [], '{"foo":"bar"}'),
  65. new Response(200, [], '{"foo":"bar"}')
  66. ],
  67. $mock
  68. );
  69. $client->doBodyLocation(['foo' => 'Foo']);
  70. $this->assertEquals('foo=Foo', (string) $mock->getLastRequest()->getBody());
  71. $client->doBodyLocation([
  72. 'foo' => 'Foo',
  73. 'bar' => 'Bar',
  74. 'baz' => 'Baz'
  75. ]);
  76. $this->assertEquals('foo=Foo&bar=Bar&baz=Baz', (string) $mock->getLastRequest()->getBody());
  77. }
  78. public function testExecuteWithJsonLocation()
  79. {
  80. $mock = new MockHandler();
  81. $client = $this->getServiceClient(
  82. [
  83. new Response(200, [], '{"foo":"bar"}'),
  84. new Response(200, [], '{"foo":"bar"}')
  85. ],
  86. $mock
  87. );
  88. $client->doJsonLocation(['foo' => 'Foo']);
  89. $this->assertEquals('{"foo":"Foo"}', (string) $mock->getLastRequest()->getBody());
  90. $client->doJsonLocation([
  91. 'foo' => 'Foo',
  92. 'bar' => 'Bar',
  93. 'baz' => 'Baz'
  94. ]);
  95. $this->assertEquals('{"foo":"Foo","bar":"Bar","baz":"Baz"}', (string) $mock->getLastRequest()->getBody());
  96. }
  97. public function testExecuteWithHeaderLocation()
  98. {
  99. $mock = new MockHandler();
  100. $client = $this->getServiceClient(
  101. [
  102. new Response(200, [], '{"foo":"bar"}'),
  103. new Response(200, [], '{"foo":"bar"}')
  104. ],
  105. $mock
  106. );
  107. $client->doHeaderLocation(['foo' => 'Foo']);
  108. $this->assertEquals(['Foo'], $mock->getLastRequest()->getHeader('foo'));
  109. $client->doHeaderLocation([
  110. 'foo' => 'Foo',
  111. 'bar' => 'Bar',
  112. 'baz' => 'Baz'
  113. ]);
  114. $this->assertEquals(['Foo'], $mock->getLastRequest()->getHeader('foo'));
  115. $this->assertEquals(['Bar'], $mock->getLastRequest()->getHeader('bar'));
  116. $this->assertEquals(['Baz'], $mock->getLastRequest()->getHeader('baz'));
  117. }
  118. public function testExecuteWithXmlLocation()
  119. {
  120. $mock = new MockHandler();
  121. $client = $this->getServiceClient(
  122. [
  123. new Response(200, [], '{"foo":"bar"}'),
  124. new Response(200, [], '{"foo":"bar"}')
  125. ],
  126. $mock
  127. );
  128. $client->doXmlLocation(['foo' => 'Foo']);
  129. $this->assertEquals(
  130. "<?xml version=\"1.0\"?>\n<Request><foo>Foo</foo></Request>\n",
  131. (string) $mock->getLastRequest()->getBody()
  132. );
  133. $client->doXmlLocation([
  134. 'foo' => 'Foo',
  135. 'bar' => 'Bar',
  136. 'baz' => 'Baz'
  137. ]);
  138. $this->assertEquals(
  139. "<?xml version=\"1.0\"?>\n<Request><foo>Foo</foo><bar>Bar</bar><baz>Baz</baz></Request>\n",
  140. $mock->getLastRequest()->getBody()
  141. );
  142. }
  143. public function testExecuteWithMultiPartLocation()
  144. {
  145. $mock = new MockHandler();
  146. $client = $this->getServiceClient(
  147. [
  148. new Response(200, [], '{"foo":"bar"}'),
  149. new Response(200, [], '{"foo":"bar"}'),
  150. new Response(200, [], '{"foo":"bar"}')
  151. ],
  152. $mock
  153. );
  154. $client->doMultiPartLocation(['foo' => 'Foo']);
  155. $multiPartRequestBody = (string) $mock->getLastRequest()->getBody();
  156. $this->assertContains('name="foo"', $multiPartRequestBody);
  157. $this->assertContains('Foo', $multiPartRequestBody);
  158. $client->doMultiPartLocation([
  159. 'foo' => 'Foo',
  160. 'bar' => 'Bar',
  161. 'baz' => 'Baz'
  162. ]);
  163. $multiPartRequestBody = (string) $mock->getLastRequest()->getBody();
  164. $this->assertContains('name="foo"', $multiPartRequestBody);
  165. $this->assertContains('Foo', $multiPartRequestBody);
  166. $this->assertContains('name="bar"', $multiPartRequestBody);
  167. $this->assertContains('Bar', $multiPartRequestBody);
  168. $this->assertContains('name="baz"', $multiPartRequestBody);
  169. $this->assertContains('Baz', $multiPartRequestBody);
  170. $client->doMultiPartLocation([
  171. 'file' => fopen(dirname(__FILE__) . '/Asset/test.html', 'r'),
  172. ]);
  173. $multiPartRequestBody = (string) $mock->getLastRequest()->getBody();
  174. $this->assertContains('name="file"', $multiPartRequestBody);
  175. $this->assertContains('filename="test.html"', $multiPartRequestBody);
  176. $this->assertContains('<title>Title</title>', $multiPartRequestBody);
  177. }
  178. public function testHasConfig()
  179. {
  180. $client = new HttpClient();
  181. $description = new Description([]);
  182. $guzzle = new GuzzleClient(
  183. $client,
  184. $description,
  185. $this->commandToRequestTransformer(),
  186. $this->responseToResultTransformer(),
  187. null,
  188. ['foo' => 'bar']
  189. );
  190. $this->assertSame($client, $guzzle->getHttpClient());
  191. $this->assertSame($description, $guzzle->getDescription());
  192. $this->assertEquals('bar', $guzzle->getConfig('foo'));
  193. $this->assertEquals([], $guzzle->getConfig('defaults'));
  194. $guzzle->setConfig('abc', 'listen');
  195. $this->assertEquals('listen', $guzzle->getConfig('abc'));
  196. }
  197. public function testAddsValidateHandlerWhenTrue()
  198. {
  199. $client = new HttpClient();
  200. $description = new Description([]);
  201. $guzzle = new GuzzleClient(
  202. $client,
  203. $description,
  204. $this->commandToRequestTransformer(),
  205. $this->responseToResultTransformer(),
  206. null,
  207. [
  208. 'validate' => true,
  209. 'process' => false
  210. ]
  211. );
  212. $handlers = explode("\n", $guzzle->getHandlerStack()->__toString());
  213. $handlers = array_filter($handlers);
  214. $this->assertCount(3, $handlers);
  215. }
  216. public function testDisablesHandlersWhenFalse()
  217. {
  218. $client = new HttpClient();
  219. $description = new Description([]);
  220. $guzzle = new GuzzleClient(
  221. $client,
  222. $description,
  223. $this->commandToRequestTransformer(),
  224. $this->responseToResultTransformer(),
  225. null,
  226. [
  227. 'validate' => false,
  228. 'process' => false
  229. ]
  230. );
  231. $handlers = explode("\n", $guzzle->getHandlerStack()->__toString());
  232. $handlers = array_filter($handlers);
  233. $this->assertCount(1, $handlers);
  234. }
  235. public function testValidateDescription()
  236. {
  237. $client = new HttpClient();
  238. $description = new Description(
  239. [
  240. 'name' => 'Testing API ',
  241. 'baseUri' => 'http://httpbin.org/',
  242. 'operations' => [
  243. 'Foo' => [
  244. 'httpMethod' => 'GET',
  245. 'uri' => '/get',
  246. 'parameters' => [
  247. 'bar' => [
  248. 'type' => 'string',
  249. 'required' => false,
  250. 'description' => 'Bar',
  251. 'location' => 'query'
  252. ],
  253. 'baz' => [
  254. 'type' => 'string',
  255. 'required' => false,
  256. 'description' => 'baz',
  257. 'location' => 'query'
  258. ],
  259. ],
  260. 'responseModel' => 'Foo'
  261. ],
  262. ],
  263. 'models' => [
  264. 'Foo' => [
  265. 'type' => 'object',
  266. 'properties' => [
  267. 'id' => [
  268. 'location' => 'json',
  269. 'type' => 'string'
  270. ],
  271. 'location' => [
  272. 'location' => 'header',
  273. 'sentAs' => 'Location',
  274. 'type' => 'string'
  275. ],
  276. 'age' => [
  277. 'location' => 'json',
  278. 'type' => 'integer'
  279. ],
  280. 'statusCode' => [
  281. 'location' => 'statusCode',
  282. 'type' => 'integer'
  283. ],
  284. ],
  285. ],
  286. ],
  287. ]
  288. );
  289. $guzzle = new GuzzleClient(
  290. $client,
  291. $description,
  292. null,
  293. null,
  294. null,
  295. [
  296. 'validate' => true,
  297. 'process' => false
  298. ]
  299. );
  300. $command = $guzzle->getCommand('Foo', ['baz' => 'BAZ']);
  301. /** @var ResponseInterface $response */
  302. $response = $guzzle->execute($command);
  303. $this->assertInstanceOf(Response::class, $response);
  304. $this->assertEquals(200, $response->getStatusCode());
  305. }
  306. /**
  307. * @expectedException \GuzzleHttp\Command\Exception\CommandException
  308. * @expectedExceptionMessage Validation errors: [baz] is a required string: baz
  309. */
  310. public function testValidateDescriptionFailsDueMissingRequiredParameter()
  311. {
  312. $client = new HttpClient();
  313. $description = new Description(
  314. [
  315. 'name' => 'Testing API ',
  316. 'baseUri' => 'http://httpbin.org/',
  317. 'operations' => [
  318. 'Foo' => [
  319. 'httpMethod' => 'GET',
  320. 'uri' => '/get',
  321. 'parameters' => [
  322. 'bar' => [
  323. 'type' => 'string',
  324. 'required' => false,
  325. 'description' => 'Bar',
  326. 'location' => 'query'
  327. ],
  328. 'baz' => [
  329. 'type' => 'string',
  330. 'required' => true,
  331. 'description' => 'baz',
  332. 'location' => 'query'
  333. ],
  334. ],
  335. 'responseModel' => 'Foo'
  336. ],
  337. ],
  338. 'models' => [
  339. 'Foo' => [
  340. 'type' => 'object',
  341. 'properties' => [
  342. 'id' => [
  343. 'location' => 'json',
  344. 'type' => 'string'
  345. ],
  346. 'location' => [
  347. 'location' => 'header',
  348. 'sentAs' => 'Location',
  349. 'type' => 'string'
  350. ],
  351. 'age' => [
  352. 'location' => 'json',
  353. 'type' => 'integer'
  354. ],
  355. 'statusCode' => [
  356. 'location' => 'statusCode',
  357. 'type' => 'integer'
  358. ],
  359. ],
  360. ],
  361. ],
  362. ]
  363. );
  364. $guzzle = new GuzzleClient(
  365. $client,
  366. $description,
  367. null,
  368. null,
  369. null,
  370. [
  371. 'validate' => true,
  372. 'process' => false
  373. ]
  374. );
  375. $command = $guzzle->getCommand('Foo');
  376. /** @var ResultInterface $result */
  377. $result = $guzzle->execute($command);
  378. $this->assertInstanceOf(Result::class, $result);
  379. $result = $result->toArray();
  380. $this->assertEquals(200, $result['statusCode']);
  381. }
  382. /**
  383. * @expectedException \GuzzleHttp\Command\Exception\CommandException
  384. * @expectedExceptionMessage Validation errors: [baz] must be of type integer
  385. */
  386. public function testValidateDescriptionFailsDueTypeMismatch()
  387. {
  388. $client = new HttpClient();
  389. $description = new Description(
  390. [
  391. 'name' => 'Testing API ',
  392. 'baseUri' => 'http://httpbin.org/',
  393. 'operations' => [
  394. 'Foo' => [
  395. 'httpMethod' => 'GET',
  396. 'uri' => '/get',
  397. 'parameters' => [
  398. 'bar' => [
  399. 'type' => 'string',
  400. 'required' => false,
  401. 'description' => 'Bar',
  402. 'location' => 'query'
  403. ],
  404. 'baz' => [
  405. 'type' => 'integer',
  406. 'required' => true,
  407. 'description' => 'baz',
  408. 'location' => 'query'
  409. ],
  410. ],
  411. 'responseModel' => 'Foo'
  412. ],
  413. ],
  414. 'models' => [
  415. 'Foo' => [
  416. 'type' => 'object',
  417. 'properties' => [
  418. 'id' => [
  419. 'location' => 'json',
  420. 'type' => 'string'
  421. ],
  422. 'location' => [
  423. 'location' => 'header',
  424. 'sentAs' => 'Location',
  425. 'type' => 'string'
  426. ],
  427. 'age' => [
  428. 'location' => 'json',
  429. 'type' => 'integer'
  430. ],
  431. 'statusCode' => [
  432. 'location' => 'statusCode',
  433. 'type' => 'integer'
  434. ],
  435. ],
  436. ],
  437. ],
  438. ]
  439. );
  440. $guzzle = new GuzzleClient(
  441. $client,
  442. $description,
  443. null,
  444. null,
  445. null,
  446. [
  447. 'validate' => true,
  448. 'process' => false
  449. ]
  450. );
  451. $command = $guzzle->getCommand('Foo', ['baz' => 'Hello']);
  452. /** @var ResultInterface $result */
  453. $result = $guzzle->execute($command);
  454. $this->assertInstanceOf(Result::class, $result);
  455. $result = $result->toArray();
  456. $this->assertEquals(200, $result['statusCode']);
  457. }
  458. public function testValidateDescriptionDoesNotFailWhenSendingIntegerButExpectingString()
  459. {
  460. $client = new HttpClient();
  461. $description = new Description(
  462. [
  463. 'name' => 'Testing API ',
  464. 'baseUri' => 'http://httpbin.org/',
  465. 'operations' => [
  466. 'Foo' => [
  467. 'httpMethod' => 'GET',
  468. 'uri' => '/get',
  469. 'parameters' => [
  470. 'bar' => [
  471. 'type' => 'string',
  472. 'required' => false,
  473. 'description' => 'Bar',
  474. 'location' => 'query'
  475. ],
  476. 'baz' => [
  477. 'type' => 'string',
  478. 'required' => true,
  479. 'description' => 'baz',
  480. 'location' => 'query'
  481. ],
  482. ],
  483. 'responseModel' => 'Foo'
  484. ],
  485. ],
  486. 'models' => [
  487. 'Foo' => [
  488. 'type' => 'object',
  489. 'properties' => [
  490. 'id' => [
  491. 'location' => 'json',
  492. 'type' => 'string'
  493. ],
  494. 'location' => [
  495. 'location' => 'header',
  496. 'sentAs' => 'Location',
  497. 'type' => 'string'
  498. ],
  499. 'age' => [
  500. 'location' => 'json',
  501. 'type' => 'integer'
  502. ],
  503. 'statusCode' => [
  504. 'location' => 'statusCode',
  505. 'type' => 'integer'
  506. ],
  507. ],
  508. ],
  509. ],
  510. ]
  511. );
  512. $guzzle = new GuzzleClient($client, $description);
  513. $command = $guzzle->getCommand('Foo', ['baz' => 42]);
  514. /** @var ResultInterface $result */
  515. $result = $guzzle->execute($command);
  516. $this->assertInstanceOf(Result::class, $result);
  517. $result = $result->toArray();
  518. $this->assertEquals(200, $result['statusCode']);
  519. }
  520. public function testMagicMethodExecutesCommands()
  521. {
  522. $client = new HttpClient();
  523. $description = new Description(
  524. [
  525. 'name' => 'Testing API ',
  526. 'baseUri' => 'http://httpbin.org/',
  527. 'operations' => [
  528. 'Foo' => [
  529. 'httpMethod' => 'GET',
  530. 'uri' => '/get',
  531. 'parameters' => [
  532. 'bar' => [
  533. 'type' => 'string',
  534. 'required' => false,
  535. 'description' => 'Bar',
  536. 'location' => 'query'
  537. ],
  538. 'baz' => [
  539. 'type' => 'string',
  540. 'required' => true,
  541. 'description' => 'baz',
  542. 'location' => 'query'
  543. ],
  544. ],
  545. 'responseModel' => 'Foo'
  546. ],
  547. ],
  548. 'models' => [
  549. 'Foo' => [
  550. 'type' => 'object',
  551. 'properties' => [
  552. 'id' => [
  553. 'location' => 'json',
  554. 'type' => 'string'
  555. ],
  556. 'location' => [
  557. 'location' => 'header',
  558. 'sentAs' => 'Location',
  559. 'type' => 'string'
  560. ],
  561. 'age' => [
  562. 'location' => 'json',
  563. 'type' => 'integer'
  564. ],
  565. 'statusCode' => [
  566. 'location' => 'statusCode',
  567. 'type' => 'integer'
  568. ],
  569. ],
  570. ],
  571. ],
  572. ]
  573. );
  574. $guzzle = $this->getMockBuilder(GuzzleClient::class)
  575. ->setConstructorArgs([
  576. $client,
  577. $description
  578. ])
  579. ->setMethods(['execute'])
  580. ->getMock();
  581. $guzzle->expects($this->once())
  582. ->method('execute')
  583. ->will($this->returnValue('foo'));
  584. $this->assertEquals('foo', $guzzle->foo([]));
  585. }
  586. /**
  587. * @expectedException \InvalidArgumentException
  588. * @expectedExceptionMessage No operation found named Foo
  589. */
  590. public function testThrowsWhenOperationNotFoundInDescription()
  591. {
  592. $client = new HttpClient();
  593. $description = new Description([]);
  594. $guzzle = new GuzzleClient(
  595. $client,
  596. $description,
  597. $this->commandToRequestTransformer(),
  598. $this->responseToResultTransformer()
  599. );
  600. $guzzle->getCommand('foo');
  601. }
  602. public function testReturnsProcessedResponse()
  603. {
  604. $client = new HttpClient();
  605. $description = new Description(
  606. [
  607. 'name' => 'Testing API ',
  608. 'baseUri' => 'http://httpbin.org/',
  609. 'operations' => [
  610. 'Foo' => [
  611. 'httpMethod' => 'GET',
  612. 'uri' => '/get',
  613. 'parameters' => [
  614. 'bar' => [
  615. 'type' => 'string',
  616. 'required' => false,
  617. 'description' => 'Bar',
  618. 'location' => 'query'
  619. ],
  620. 'baz' => [
  621. 'type' => 'string',
  622. 'required' => true,
  623. 'description' => 'baz',
  624. 'location' => 'query'
  625. ],
  626. ],
  627. 'responseModel' => 'Foo'
  628. ],
  629. ],
  630. 'models' => [
  631. 'Foo' => [
  632. 'type' => 'object',
  633. 'properties' => [
  634. 'id' => [
  635. 'location' => 'json',
  636. 'type' => 'string'
  637. ],
  638. 'location' => [
  639. 'location' => 'header',
  640. 'sentAs' => 'Location',
  641. 'type' => 'string'
  642. ],
  643. 'age' => [
  644. 'location' => 'json',
  645. 'type' => 'integer'
  646. ],
  647. 'statusCode' => [
  648. 'location' => 'statusCode',
  649. 'type' => 'integer'
  650. ],
  651. ],
  652. ],
  653. ],
  654. ]
  655. );
  656. $guzzle = new GuzzleClient($client, $description, null, null);
  657. $command = $guzzle->getCommand('foo', ['baz' => 'BAZ']);
  658. /** @var ResultInterface $result */
  659. $result = $guzzle->execute($command);
  660. $this->assertInstanceOf(Result::class, $result);
  661. $result = $result->toArray();
  662. $this->assertEquals(200, $result['statusCode']);
  663. }
  664. private function getServiceClient(
  665. array $responses,
  666. MockHandler $mock = null,
  667. callable $commandToRequestTransformer = null
  668. ) {
  669. $mock = $mock ?: new MockHandler();
  670. foreach ($responses as $response) {
  671. $mock->append($response);
  672. }
  673. return new GuzzleClient(
  674. new HttpClient([
  675. 'handler' => $mock
  676. ]),
  677. $this->getDescription(),
  678. $commandToRequestTransformer,
  679. $this->responseToResultTransformer(),
  680. null,
  681. ['foo' => 'bar']
  682. );
  683. }
  684. private function commandToRequestTransformer()
  685. {
  686. return function (CommandInterface $command) {
  687. $data = $command->toArray();
  688. $data['action'] = $command->getName();
  689. return new Request('POST', '/', [], http_build_query($data));
  690. };
  691. }
  692. private function responseToResultTransformer()
  693. {
  694. return function (ResponseInterface $response, RequestInterface $request, CommandInterface $command) {
  695. $data = \GuzzleHttp\json_decode($response->getBody(), true);
  696. parse_str($request->getBody(), $data['_request']);
  697. return new Result($data);
  698. };
  699. }
  700. private function getDescription()
  701. {
  702. return new Description(
  703. [
  704. 'name' => 'Testing API ',
  705. 'baseUri' => 'http://httpbin.org/',
  706. 'operations' => [
  707. 'doThatThingYouDo' => [
  708. 'responseModel' => 'Bar'
  709. ],
  710. 'doThatThingOtherYouDo' => [
  711. 'responseModel' => 'Foo'
  712. ],
  713. 'doQueryLocation' => [
  714. 'httpMethod' => 'GET',
  715. 'uri' => '/queryLocation',
  716. 'parameters' => [
  717. 'foo' => [
  718. 'type' => 'string',
  719. 'required' => false,
  720. 'description' => 'Testing query request location',
  721. 'location' => 'query'
  722. ],
  723. 'bar' => [
  724. 'type' => 'string',
  725. 'required' => false,
  726. 'description' => 'Testing query request location',
  727. 'location' => 'query'
  728. ],
  729. 'baz' => [
  730. 'type' => 'string',
  731. 'required' => false,
  732. 'description' => 'Testing query request location',
  733. 'location' => 'query'
  734. ]
  735. ],
  736. 'responseModel' => 'QueryResponse'
  737. ],
  738. 'doBodyLocation' => [
  739. 'httpMethod' => 'GET',
  740. 'uri' => '/bodyLocation',
  741. 'parameters' => [
  742. 'foo' => [
  743. 'type' => 'string',
  744. 'required' => false,
  745. 'description' => 'Testing body request location',
  746. 'location' => 'body'
  747. ],
  748. 'bar' => [
  749. 'type' => 'string',
  750. 'required' => false,
  751. 'description' => 'Testing body request location',
  752. 'location' => 'body'
  753. ],
  754. 'baz' => [
  755. 'type' => 'string',
  756. 'required' => false,
  757. 'description' => 'Testing body request location',
  758. 'location' => 'body'
  759. ]
  760. ],
  761. 'responseModel' => 'BodyResponse'
  762. ],
  763. 'doJsonLocation' => [
  764. 'httpMethod' => 'GET',
  765. 'uri' => '/jsonLocation',
  766. 'parameters' => [
  767. 'foo' => [
  768. 'type' => 'string',
  769. 'required' => false,
  770. 'description' => 'Testing json request location',
  771. 'location' => 'json'
  772. ],
  773. 'bar' => [
  774. 'type' => 'string',
  775. 'required' => false,
  776. 'description' => 'Testing json request location',
  777. 'location' => 'json'
  778. ],
  779. 'baz' => [
  780. 'type' => 'string',
  781. 'required' => false,
  782. 'description' => 'Testing json request location',
  783. 'location' => 'json'
  784. ]
  785. ],
  786. 'responseModel' => 'JsonResponse'
  787. ],
  788. 'doHeaderLocation' => [
  789. 'httpMethod' => 'GET',
  790. 'uri' => '/headerLocation',
  791. 'parameters' => [
  792. 'foo' => [
  793. 'type' => 'string',
  794. 'required' => false,
  795. 'description' => 'Testing header request location',
  796. 'location' => 'header'
  797. ],
  798. 'bar' => [
  799. 'type' => 'string',
  800. 'required' => false,
  801. 'description' => 'Testing header request location',
  802. 'location' => 'header'
  803. ],
  804. 'baz' => [
  805. 'type' => 'string',
  806. 'required' => false,
  807. 'description' => 'Testing header request location',
  808. 'location' => 'header'
  809. ]
  810. ],
  811. 'responseModel' => 'HeaderResponse'
  812. ],
  813. 'doXmlLocation' => [
  814. 'httpMethod' => 'GET',
  815. 'uri' => '/xmlLocation',
  816. 'parameters' => [
  817. 'foo' => [
  818. 'type' => 'string',
  819. 'required' => false,
  820. 'description' => 'Testing xml request location',
  821. 'location' => 'xml'
  822. ],
  823. 'bar' => [
  824. 'type' => 'string',
  825. 'required' => false,
  826. 'description' => 'Testing xml request location',
  827. 'location' => 'xml'
  828. ],
  829. 'baz' => [
  830. 'type' => 'string',
  831. 'required' => false,
  832. 'description' => 'Testing xml request location',
  833. 'location' => 'xml'
  834. ]
  835. ],
  836. 'responseModel' => 'XmlResponse'
  837. ],
  838. 'doMultiPartLocation' => [
  839. 'httpMethod' => 'POST',
  840. 'uri' => '/multipartLocation',
  841. 'parameters' => [
  842. 'foo' => [
  843. 'type' => 'string',
  844. 'required' => false,
  845. 'description' => 'Testing multipart request location',
  846. 'location' => 'multipart'
  847. ],
  848. 'bar' => [
  849. 'type' => 'string',
  850. 'required' => false,
  851. 'description' => 'Testing multipart request location',
  852. 'location' => 'multipart'
  853. ],
  854. 'baz' => [
  855. 'type' => 'string',
  856. 'required' => false,
  857. 'description' => 'Testing multipart request location',
  858. 'location' => 'multipart'
  859. ],
  860. 'file' => [
  861. 'type' => 'any',
  862. 'required' => false,
  863. 'description' => 'Testing multipart request location',
  864. 'location' => 'multipart'
  865. ]
  866. ],
  867. 'responseModel' => 'MultipartResponse'
  868. ],
  869. ],
  870. 'models' => [
  871. 'Foo' => [
  872. 'type' => 'object',
  873. 'properties' => [
  874. 'code' => [
  875. 'location' => 'statusCode'
  876. ]
  877. ]
  878. ],
  879. 'Bar' => [
  880. 'type' => 'object',
  881. 'properties' => [
  882. 'code' => ['
  883. location' => 'statusCode'
  884. ]
  885. ]
  886. ]
  887. ]
  888. ]
  889. );
  890. }
  891. public function testDocumentationExampleFromReadme()
  892. {
  893. $client = new HttpClient();
  894. $description = new Description([
  895. 'baseUrl' => 'http://httpbin.org/',
  896. 'operations' => [
  897. 'testing' => [
  898. 'httpMethod' => 'GET',
  899. 'uri' => '/get{?foo}',
  900. 'responseModel' => 'getResponse',
  901. 'parameters' => [
  902. 'foo' => [
  903. 'type' => 'string',
  904. 'location' => 'uri'
  905. ],
  906. 'bar' => [
  907. 'type' => 'string',
  908. 'location' => 'query'
  909. ]
  910. ]
  911. ]
  912. ],
  913. 'models' => [
  914. 'getResponse' => [
  915. 'type' => 'object',
  916. 'additionalProperties' => [
  917. 'location' => 'json'
  918. ]
  919. ]
  920. ]
  921. ]);
  922. $guzzle = new GuzzleClient($client, $description);
  923. $result = $guzzle->testing(['foo' => 'bar']);
  924. $this->assertEquals('bar', $result['args']['foo']);
  925. }
  926. public function testDescriptionWithExtends()
  927. {
  928. $client = new HttpClient();
  929. $description = new Description([
  930. 'baseUrl' => 'http://httpbin.org/',
  931. 'operations' => [
  932. 'testing' => [
  933. 'httpMethod' => 'GET',
  934. 'uri' => '/get',
  935. 'responseModel' => 'getResponse',
  936. 'parameters' => [
  937. 'foo' => [
  938. 'type' => 'string',
  939. 'default' => 'foo',
  940. 'location' => 'query'
  941. ]
  942. ]
  943. ],
  944. 'testing_extends' => [
  945. 'extends' => 'testing',
  946. 'responseModel' => 'getResponse',
  947. 'parameters' => [
  948. 'bar' => [
  949. 'type' => 'string',
  950. 'location' => 'query'
  951. ]
  952. ]
  953. ],
  954. ],
  955. 'models' => [
  956. 'getResponse' => [
  957. 'type' => 'object',
  958. 'additionalProperties' => [
  959. 'location' => 'json'
  960. ]
  961. ]
  962. ]
  963. ]);
  964. $guzzle = new GuzzleClient($client, $description);
  965. $result = $guzzle->testing_extends(['bar' => 'bar']);
  966. $this->assertEquals('bar', $result['args']['bar']);
  967. $this->assertEquals('foo', $result['args']['foo']);
  968. }
  969. }