GuzzleClientTest.php 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038
  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. }