MiddlewareDispatcherTest.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace Test\AppFramework\Middleware;
  8. use OC\AppFramework\Http\Request;
  9. use OC\AppFramework\Middleware\MiddlewareDispatcher;
  10. use OCP\AppFramework\Http\Response;
  11. use OCP\AppFramework\Middleware;
  12. use OCP\IConfig;
  13. use OCP\IRequestId;
  14. // needed to test ordering
  15. class TestMiddleware extends Middleware {
  16. public static $beforeControllerCalled = 0;
  17. public static $afterControllerCalled = 0;
  18. public static $afterExceptionCalled = 0;
  19. public static $beforeOutputCalled = 0;
  20. public $beforeControllerOrder = 0;
  21. public $afterControllerOrder = 0;
  22. public $afterExceptionOrder = 0;
  23. public $beforeOutputOrder = 0;
  24. public $controller;
  25. public $methodName;
  26. public $exception;
  27. public $response;
  28. public $output;
  29. private $beforeControllerThrowsEx;
  30. /**
  31. * @param boolean $beforeControllerThrowsEx
  32. */
  33. public function __construct($beforeControllerThrowsEx) {
  34. self::$beforeControllerCalled = 0;
  35. self::$afterControllerCalled = 0;
  36. self::$afterExceptionCalled = 0;
  37. self::$beforeOutputCalled = 0;
  38. $this->beforeControllerThrowsEx = $beforeControllerThrowsEx;
  39. }
  40. public function beforeController($controller, $methodName) {
  41. self::$beforeControllerCalled++;
  42. $this->beforeControllerOrder = self::$beforeControllerCalled;
  43. $this->controller = $controller;
  44. $this->methodName = $methodName;
  45. if ($this->beforeControllerThrowsEx) {
  46. throw new \Exception();
  47. }
  48. }
  49. public function afterException($controller, $methodName, \Exception $exception) {
  50. self::$afterExceptionCalled++;
  51. $this->afterExceptionOrder = self::$afterExceptionCalled;
  52. $this->controller = $controller;
  53. $this->methodName = $methodName;
  54. $this->exception = $exception;
  55. parent::afterException($controller, $methodName, $exception);
  56. }
  57. public function afterController($controller, $methodName, Response $response) {
  58. self::$afterControllerCalled++;
  59. $this->afterControllerOrder = self::$afterControllerCalled;
  60. $this->controller = $controller;
  61. $this->methodName = $methodName;
  62. $this->response = $response;
  63. return parent::afterController($controller, $methodName, $response);
  64. }
  65. public function beforeOutput($controller, $methodName, $output) {
  66. self::$beforeOutputCalled++;
  67. $this->beforeOutputOrder = self::$beforeOutputCalled;
  68. $this->controller = $controller;
  69. $this->methodName = $methodName;
  70. $this->output = $output;
  71. return parent::beforeOutput($controller, $methodName, $output);
  72. }
  73. }
  74. class MiddlewareDispatcherTest extends \Test\TestCase {
  75. public $exception;
  76. public $response;
  77. private $out;
  78. private $method;
  79. private $controller;
  80. /**
  81. * @var MiddlewareDispatcher
  82. */
  83. private $dispatcher;
  84. protected function setUp(): void {
  85. parent::setUp();
  86. $this->dispatcher = new MiddlewareDispatcher();
  87. $this->controller = $this->getControllerMock();
  88. $this->method = 'method';
  89. $this->response = new Response();
  90. $this->out = 'hi';
  91. $this->exception = new \Exception();
  92. }
  93. private function getControllerMock() {
  94. return $this->getMockBuilder('OCP\AppFramework\Controller')
  95. ->setMethods(['method'])
  96. ->setConstructorArgs(['app',
  97. new Request(
  98. ['method' => 'GET'],
  99. $this->createMock(IRequestId::class),
  100. $this->createMock(IConfig::class)
  101. )
  102. ])->getMock();
  103. }
  104. private function getMiddleware($beforeControllerThrowsEx = false) {
  105. $m1 = new TestMiddleware($beforeControllerThrowsEx);
  106. $this->dispatcher->registerMiddleware($m1);
  107. return $m1;
  108. }
  109. public function testAfterExceptionShouldReturnResponseOfMiddleware(): void {
  110. $response = new Response();
  111. $m1 = $this->getMockBuilder('\OCP\AppFramework\Middleware')
  112. ->setMethods(['afterException', 'beforeController'])
  113. ->getMock();
  114. $m1->expects($this->never())
  115. ->method('afterException');
  116. $m2 = $this->getMockBuilder('OCP\AppFramework\Middleware')
  117. ->setMethods(['afterException', 'beforeController'])
  118. ->getMock();
  119. $m2->expects($this->once())
  120. ->method('afterException')
  121. ->willReturn($response);
  122. $this->dispatcher->registerMiddleware($m1);
  123. $this->dispatcher->registerMiddleware($m2);
  124. $this->dispatcher->beforeController($this->controller, $this->method);
  125. $this->assertEquals($response, $this->dispatcher->afterException($this->controller, $this->method, $this->exception));
  126. }
  127. public function testAfterExceptionShouldThrowAgainWhenNotHandled(): void {
  128. $m1 = new TestMiddleware(false);
  129. $m2 = new TestMiddleware(true);
  130. $this->dispatcher->registerMiddleware($m1);
  131. $this->dispatcher->registerMiddleware($m2);
  132. $this->expectException(\Exception::class);
  133. $this->dispatcher->beforeController($this->controller, $this->method);
  134. $this->dispatcher->afterException($this->controller, $this->method, $this->exception);
  135. }
  136. public function testBeforeControllerCorrectArguments(): void {
  137. $m1 = $this->getMiddleware();
  138. $this->dispatcher->beforeController($this->controller, $this->method);
  139. $this->assertEquals($this->controller, $m1->controller);
  140. $this->assertEquals($this->method, $m1->methodName);
  141. }
  142. public function testAfterControllerCorrectArguments(): void {
  143. $m1 = $this->getMiddleware();
  144. $this->dispatcher->afterController($this->controller, $this->method, $this->response);
  145. $this->assertEquals($this->controller, $m1->controller);
  146. $this->assertEquals($this->method, $m1->methodName);
  147. $this->assertEquals($this->response, $m1->response);
  148. }
  149. public function testAfterExceptionCorrectArguments(): void {
  150. $m1 = $this->getMiddleware();
  151. $this->expectException(\Exception::class);
  152. $this->dispatcher->beforeController($this->controller, $this->method);
  153. $this->dispatcher->afterException($this->controller, $this->method, $this->exception);
  154. $this->assertEquals($this->controller, $m1->controller);
  155. $this->assertEquals($this->method, $m1->methodName);
  156. $this->assertEquals($this->exception, $m1->exception);
  157. }
  158. public function testBeforeOutputCorrectArguments(): void {
  159. $m1 = $this->getMiddleware();
  160. $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out);
  161. $this->assertEquals($this->controller, $m1->controller);
  162. $this->assertEquals($this->method, $m1->methodName);
  163. $this->assertEquals($this->out, $m1->output);
  164. }
  165. public function testBeforeControllerOrder(): void {
  166. $m1 = $this->getMiddleware();
  167. $m2 = $this->getMiddleware();
  168. $this->dispatcher->beforeController($this->controller, $this->method);
  169. $this->assertEquals(1, $m1->beforeControllerOrder);
  170. $this->assertEquals(2, $m2->beforeControllerOrder);
  171. }
  172. public function testAfterControllerOrder(): void {
  173. $m1 = $this->getMiddleware();
  174. $m2 = $this->getMiddleware();
  175. $this->dispatcher->afterController($this->controller, $this->method, $this->response);
  176. $this->assertEquals(2, $m1->afterControllerOrder);
  177. $this->assertEquals(1, $m2->afterControllerOrder);
  178. }
  179. public function testAfterExceptionOrder(): void {
  180. $m1 = $this->getMiddleware();
  181. $m2 = $this->getMiddleware();
  182. $this->expectException(\Exception::class);
  183. $this->dispatcher->beforeController($this->controller, $this->method);
  184. $this->dispatcher->afterException($this->controller, $this->method, $this->exception);
  185. $this->assertEquals(1, $m1->afterExceptionOrder);
  186. $this->assertEquals(1, $m2->afterExceptionOrder);
  187. }
  188. public function testBeforeOutputOrder(): void {
  189. $m1 = $this->getMiddleware();
  190. $m2 = $this->getMiddleware();
  191. $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out);
  192. $this->assertEquals(2, $m1->beforeOutputOrder);
  193. $this->assertEquals(1, $m2->beforeOutputOrder);
  194. }
  195. public function testExceptionShouldRunAfterExceptionOfOnlyPreviouslyExecutedMiddlewares(): void {
  196. $m1 = $this->getMiddleware();
  197. $m2 = $this->getMiddleware(true);
  198. $m3 = $this->createMock(Middleware::class);
  199. $m3->expects($this->never())
  200. ->method('afterException');
  201. $m3->expects($this->never())
  202. ->method('beforeController');
  203. $m3->expects($this->never())
  204. ->method('afterController');
  205. $m3->method('beforeOutput')
  206. ->willReturnArgument(2);
  207. $this->dispatcher->registerMiddleware($m3);
  208. $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out);
  209. $this->assertEquals(2, $m1->beforeOutputOrder);
  210. $this->assertEquals(1, $m2->beforeOutputOrder);
  211. }
  212. }