beforeControllerThrowsEx = $beforeControllerThrowsEx; } public function beforeController($controller, $methodName) { self::$beforeControllerCalled++; $this->beforeControllerOrder = self::$beforeControllerCalled; $this->controller = $controller; $this->methodName = $methodName; if ($this->beforeControllerThrowsEx) { throw new \Exception(); } } public function afterException($controller, $methodName, \Exception $exception) { self::$afterExceptionCalled++; $this->afterExceptionOrder = self::$afterExceptionCalled; $this->controller = $controller; $this->methodName = $methodName; $this->exception = $exception; parent::afterException($controller, $methodName, $exception); } public function afterController($controller, $methodName, Response $response) { self::$afterControllerCalled++; $this->afterControllerOrder = self::$afterControllerCalled; $this->controller = $controller; $this->methodName = $methodName; $this->response = $response; return parent::afterController($controller, $methodName, $response); } public function beforeOutput($controller, $methodName, $output) { self::$beforeOutputCalled++; $this->beforeOutputOrder = self::$beforeOutputCalled; $this->controller = $controller; $this->methodName = $methodName; $this->output = $output; return parent::beforeOutput($controller, $methodName, $output); } } class MiddlewareDispatcherTest extends \Test\TestCase { public $exception; public $response; private $out; private $method; private $controller; /** * @var MiddlewareDispatcher */ private $dispatcher; protected function setUp(): void { parent::setUp(); $this->dispatcher = new MiddlewareDispatcher(); $this->controller = $this->getControllerMock(); $this->method = 'method'; $this->response = new Response(); $this->out = 'hi'; $this->exception = new \Exception(); } private function getControllerMock() { return $this->getMockBuilder('OCP\AppFramework\Controller') ->setMethods(['method']) ->setConstructorArgs(['app', new Request( ['method' => 'GET'], $this->createMock(IRequestId::class), $this->createMock(IConfig::class) ) ])->getMock(); } private function getMiddleware($beforeControllerThrowsEx = false) { $m1 = new TestMiddleware($beforeControllerThrowsEx); $this->dispatcher->registerMiddleware($m1); return $m1; } public function testAfterExceptionShouldReturnResponseOfMiddleware(): void { $response = new Response(); $m1 = $this->getMockBuilder('\OCP\AppFramework\Middleware') ->setMethods(['afterException', 'beforeController']) ->getMock(); $m1->expects($this->never()) ->method('afterException'); $m2 = $this->getMockBuilder('OCP\AppFramework\Middleware') ->setMethods(['afterException', 'beforeController']) ->getMock(); $m2->expects($this->once()) ->method('afterException') ->willReturn($response); $this->dispatcher->registerMiddleware($m1); $this->dispatcher->registerMiddleware($m2); $this->dispatcher->beforeController($this->controller, $this->method); $this->assertEquals($response, $this->dispatcher->afterException($this->controller, $this->method, $this->exception)); } public function testAfterExceptionShouldThrowAgainWhenNotHandled(): void { $m1 = new TestMiddleware(false); $m2 = new TestMiddleware(true); $this->dispatcher->registerMiddleware($m1); $this->dispatcher->registerMiddleware($m2); $this->expectException(\Exception::class); $this->dispatcher->beforeController($this->controller, $this->method); $this->dispatcher->afterException($this->controller, $this->method, $this->exception); } public function testBeforeControllerCorrectArguments(): void { $m1 = $this->getMiddleware(); $this->dispatcher->beforeController($this->controller, $this->method); $this->assertEquals($this->controller, $m1->controller); $this->assertEquals($this->method, $m1->methodName); } public function testAfterControllerCorrectArguments(): void { $m1 = $this->getMiddleware(); $this->dispatcher->afterController($this->controller, $this->method, $this->response); $this->assertEquals($this->controller, $m1->controller); $this->assertEquals($this->method, $m1->methodName); $this->assertEquals($this->response, $m1->response); } public function testAfterExceptionCorrectArguments(): void { $m1 = $this->getMiddleware(); $this->expectException(\Exception::class); $this->dispatcher->beforeController($this->controller, $this->method); $this->dispatcher->afterException($this->controller, $this->method, $this->exception); $this->assertEquals($this->controller, $m1->controller); $this->assertEquals($this->method, $m1->methodName); $this->assertEquals($this->exception, $m1->exception); } public function testBeforeOutputCorrectArguments(): void { $m1 = $this->getMiddleware(); $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out); $this->assertEquals($this->controller, $m1->controller); $this->assertEquals($this->method, $m1->methodName); $this->assertEquals($this->out, $m1->output); } public function testBeforeControllerOrder(): void { $m1 = $this->getMiddleware(); $m2 = $this->getMiddleware(); $this->dispatcher->beforeController($this->controller, $this->method); $this->assertEquals(1, $m1->beforeControllerOrder); $this->assertEquals(2, $m2->beforeControllerOrder); } public function testAfterControllerOrder(): void { $m1 = $this->getMiddleware(); $m2 = $this->getMiddleware(); $this->dispatcher->afterController($this->controller, $this->method, $this->response); $this->assertEquals(2, $m1->afterControllerOrder); $this->assertEquals(1, $m2->afterControllerOrder); } public function testAfterExceptionOrder(): void { $m1 = $this->getMiddleware(); $m2 = $this->getMiddleware(); $this->expectException(\Exception::class); $this->dispatcher->beforeController($this->controller, $this->method); $this->dispatcher->afterException($this->controller, $this->method, $this->exception); $this->assertEquals(1, $m1->afterExceptionOrder); $this->assertEquals(1, $m2->afterExceptionOrder); } public function testBeforeOutputOrder(): void { $m1 = $this->getMiddleware(); $m2 = $this->getMiddleware(); $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out); $this->assertEquals(2, $m1->beforeOutputOrder); $this->assertEquals(1, $m2->beforeOutputOrder); } public function testExceptionShouldRunAfterExceptionOfOnlyPreviouslyExecutedMiddlewares(): void { $m1 = $this->getMiddleware(); $m2 = $this->getMiddleware(true); $m3 = $this->createMock(Middleware::class); $m3->expects($this->never()) ->method('afterException'); $m3->expects($this->never()) ->method('beforeController'); $m3->expects($this->never()) ->method('afterController'); $m3->method('beforeOutput') ->willReturnArgument(2); $this->dispatcher->registerMiddleware($m3); $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out); $this->assertEquals(2, $m1->beforeOutputOrder); $this->assertEquals(1, $m2->beforeOutputOrder); } }