HandlerStackTest.php 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <?php
  2. namespace GuzzleHttp\Tests;
  3. use GuzzleHttp\Cookie\CookieJar;
  4. use GuzzleHttp\Handler\MockHandler;
  5. use GuzzleHttp\HandlerStack;
  6. use GuzzleHttp\Psr7\Request;
  7. use GuzzleHttp\Psr7\Response;
  8. use PHPUnit\Framework\TestCase;
  9. class HandlerStackTest extends TestCase
  10. {
  11. public function testSetsHandlerInCtor()
  12. {
  13. $f = static function () {
  14. };
  15. $m1 = static function () {
  16. };
  17. $h = new HandlerStack($f, [$m1]);
  18. self::assertTrue($h->hasHandler());
  19. }
  20. /**
  21. * @doesNotPerformAssertions
  22. */
  23. public function testCanSetDifferentHandlerAfterConstruction()
  24. {
  25. $f = static function () {
  26. };
  27. $h = new HandlerStack();
  28. $h->setHandler($f);
  29. $h->resolve();
  30. }
  31. public function testEnsuresHandlerIsSet()
  32. {
  33. $this->expectException(\LogicException::class);
  34. $h = new HandlerStack();
  35. $h->resolve();
  36. }
  37. public function testPushInOrder()
  38. {
  39. $meths = $this->getFunctions();
  40. $builder = new HandlerStack();
  41. $builder->setHandler($meths[1]);
  42. $builder->push($meths[2]);
  43. $builder->push($meths[3]);
  44. $builder->push($meths[4]);
  45. $composed = $builder->resolve();
  46. self::assertSame('Hello - test123', $composed('test'));
  47. self::assertSame(
  48. [['a', 'test'], ['b', 'test1'], ['c', 'test12']],
  49. $meths[0]
  50. );
  51. }
  52. public function testUnshiftsInReverseOrder()
  53. {
  54. $meths = $this->getFunctions();
  55. $builder = new HandlerStack();
  56. $builder->setHandler($meths[1]);
  57. $builder->unshift($meths[2]);
  58. $builder->unshift($meths[3]);
  59. $builder->unshift($meths[4]);
  60. $composed = $builder->resolve();
  61. self::assertSame('Hello - test321', $composed('test'));
  62. self::assertSame(
  63. [['c', 'test'], ['b', 'test3'], ['a', 'test32']],
  64. $meths[0]
  65. );
  66. }
  67. public function testCanRemoveMiddlewareByInstance()
  68. {
  69. $meths = $this->getFunctions();
  70. $builder = new HandlerStack();
  71. $builder->setHandler($meths[1]);
  72. $builder->push($meths[2]);
  73. $builder->push($meths[2]);
  74. $builder->push($meths[3]);
  75. $builder->push($meths[4]);
  76. $builder->push($meths[2]);
  77. $builder->remove($meths[3]);
  78. $composed = $builder->resolve();
  79. self::assertSame('Hello - test1131', $composed('test'));
  80. }
  81. public function testCanPrintMiddleware()
  82. {
  83. $meths = $this->getFunctions();
  84. $builder = new HandlerStack();
  85. $builder->setHandler($meths[1]);
  86. $builder->push($meths[2], 'a');
  87. $builder->push([__CLASS__, 'foo']);
  88. $builder->push([$this, 'bar']);
  89. $builder->push(__CLASS__.'::foo');
  90. $lines = \explode("\n", (string) $builder);
  91. self::assertStringContainsString("> 4) Name: 'a', Function: callable(", $lines[0]);
  92. self::assertStringContainsString("> 3) Name: '', Function: callable(GuzzleHttp\\Tests\\HandlerStackTest::foo)", $lines[1]);
  93. self::assertStringContainsString("> 2) Name: '', Function: callable(['GuzzleHttp\\Tests\\HandlerStackTest', 'bar'])", $lines[2]);
  94. self::assertStringContainsString("> 1) Name: '', Function: callable(GuzzleHttp\\Tests\\HandlerStackTest::foo)", $lines[3]);
  95. self::assertStringContainsString('< 0) Handler: callable(', $lines[4]);
  96. self::assertStringContainsString("< 1) Name: '', Function: callable(GuzzleHttp\\Tests\\HandlerStackTest::foo)", $lines[5]);
  97. self::assertStringContainsString("< 2) Name: '', Function: callable(['GuzzleHttp\\Tests\\HandlerStackTest', 'bar'])", $lines[6]);
  98. self::assertStringContainsString("< 3) Name: '', Function: callable(GuzzleHttp\\Tests\\HandlerStackTest::foo)", $lines[7]);
  99. self::assertStringContainsString("< 4) Name: 'a', Function: callable(", $lines[8]);
  100. }
  101. public function testCanAddBeforeByName()
  102. {
  103. $meths = $this->getFunctions();
  104. $builder = new HandlerStack();
  105. $builder->setHandler($meths[1]);
  106. $builder->push($meths[2], 'foo');
  107. $builder->before('foo', $meths[3], 'baz');
  108. $builder->before('baz', $meths[4], 'bar');
  109. $builder->before('baz', $meths[4], 'qux');
  110. $lines = \explode("\n", (string) $builder);
  111. self::assertStringContainsString('> 4) Name: \'bar\'', $lines[0]);
  112. self::assertStringContainsString('> 3) Name: \'qux\'', $lines[1]);
  113. self::assertStringContainsString('> 2) Name: \'baz\'', $lines[2]);
  114. self::assertStringContainsString('> 1) Name: \'foo\'', $lines[3]);
  115. }
  116. public function testEnsuresHandlerExistsByName()
  117. {
  118. $this->expectException(\InvalidArgumentException::class);
  119. $builder = new HandlerStack();
  120. $builder->before('foo', static function () {
  121. });
  122. }
  123. public function testCanAddAfterByName()
  124. {
  125. $meths = $this->getFunctions();
  126. $builder = new HandlerStack();
  127. $builder->setHandler($meths[1]);
  128. $builder->push($meths[2], 'a');
  129. $builder->push($meths[3], 'b');
  130. $builder->after('a', $meths[4], 'c');
  131. $builder->after('b', $meths[4], 'd');
  132. $lines = \explode("\n", (string) $builder);
  133. self::assertStringContainsString('4) Name: \'a\'', $lines[0]);
  134. self::assertStringContainsString('3) Name: \'c\'', $lines[1]);
  135. self::assertStringContainsString('2) Name: \'b\'', $lines[2]);
  136. self::assertStringContainsString('1) Name: \'d\'', $lines[3]);
  137. }
  138. public function testPicksUpCookiesFromRedirects()
  139. {
  140. $mock = new MockHandler([
  141. new Response(301, [
  142. 'Location' => 'http://foo.com/baz',
  143. 'Set-Cookie' => 'foo=bar; Domain=foo.com',
  144. ]),
  145. new Response(200),
  146. ]);
  147. $handler = HandlerStack::create($mock);
  148. $request = new Request('GET', 'http://foo.com/bar');
  149. $jar = new CookieJar();
  150. $response = $handler($request, [
  151. 'allow_redirects' => true,
  152. 'cookies' => $jar,
  153. ])->wait();
  154. self::assertSame(200, $response->getStatusCode());
  155. $lastRequest = $mock->getLastRequest();
  156. self::assertSame('http://foo.com/baz', (string) $lastRequest->getUri());
  157. self::assertSame('foo=bar', $lastRequest->getHeaderLine('Cookie'));
  158. }
  159. private function getFunctions()
  160. {
  161. $calls = [];
  162. $a = static function (callable $next) use (&$calls) {
  163. return static function ($v) use ($next, &$calls) {
  164. $calls[] = ['a', $v];
  165. return $next($v.'1');
  166. };
  167. };
  168. $b = static function (callable $next) use (&$calls) {
  169. return static function ($v) use ($next, &$calls) {
  170. $calls[] = ['b', $v];
  171. return $next($v.'2');
  172. };
  173. };
  174. $c = static function (callable $next) use (&$calls) {
  175. return static function ($v) use ($next, &$calls) {
  176. $calls[] = ['c', $v];
  177. return $next($v.'3');
  178. };
  179. };
  180. $handler = static function ($v) {
  181. return 'Hello - '.$v;
  182. };
  183. return [&$calls, $handler, $a, $b, $c];
  184. }
  185. public static function foo()
  186. {
  187. }
  188. public function bar()
  189. {
  190. }
  191. }