apiKey = $this->createMock(ApiKey::class); $this->handler = $this->createMock(RequestHandlerInterface::class); $this->domainService = $this->createMock(DomainServiceInterface::class); $this->middleware = new OverrideDomainMiddleware($this->domainService); } #[Test] public function nextMiddlewareIsCalledWhenApiKeyDoesNotHaveProperRole(): void { $request = $this->requestWithApiKey(); $response = new Response(); $this->apiKey->expects($this->once())->method('hasRole')->with(Role::DOMAIN_SPECIFIC)->willReturn(false); $this->handler->expects($this->once())->method('handle')->with($request)->willReturn($response); $this->domainService->expects($this->never())->method('getDomain'); $result = $this->middleware->process($request, $this->handler); self::assertSame($response, $result); } #[Test, DataProvider('provideBodies')] public function overwritesRequestBodyWhenMethodIsPost(Domain $domain, array $body, array $expectedBody): void { $request = $this->requestWithApiKey()->withMethod('POST')->withParsedBody($body); $this->apiKey->expects($this->once())->method('hasRole')->with(Role::DOMAIN_SPECIFIC)->willReturn(true); $this->apiKey->expects($this->once())->method('getRoleMeta')->with(Role::DOMAIN_SPECIFIC)->willReturn( ['domain_id' => '123'], ); $this->domainService->expects($this->once())->method('getDomain')->with('123')->willReturn($domain); $this->handler->expects($this->once())->method('handle')->with($this->callback( function (ServerRequestInterface $req) use ($expectedBody): bool { Assert::assertEquals($req->getParsedBody(), $expectedBody); return true; }, ))->willReturn(new Response()); $this->middleware->process($request, $this->handler); } public static function provideBodies(): iterable { yield 'no domain provided' => [ Domain::withAuthority('foo.com'), [], [ShortUrlInputFilter::DOMAIN => 'foo.com'], ]; yield 'other domain provided' => [ Domain::withAuthority('bar.com'), [ShortUrlInputFilter::DOMAIN => 'foo.com'], [ShortUrlInputFilter::DOMAIN => 'bar.com'], ]; yield 'same domain provided' => [ Domain::withAuthority('baz.com'), [ShortUrlInputFilter::DOMAIN => 'baz.com'], [ShortUrlInputFilter::DOMAIN => 'baz.com'], ]; yield 'more body params' => [ Domain::withAuthority('s.test'), [ShortUrlInputFilter::DOMAIN => 'baz.com', 'something' => 'else', 'foo' => 123], [ShortUrlInputFilter::DOMAIN => 's.test', 'something' => 'else', 'foo' => 123], ]; } #[Test, DataProvider('provideMethods')] public function setsRequestAttributeWhenMethodIsNotPost(string $method): void { $domain = Domain::withAuthority('something.com'); $request = $this->requestWithApiKey()->withMethod($method); $this->apiKey->expects($this->once())->method('hasRole')->with(Role::DOMAIN_SPECIFIC)->willReturn(true); $this->apiKey->expects($this->once())->method('getRoleMeta')->with(Role::DOMAIN_SPECIFIC)->willReturn( ['domain_id' => '123'], ); $this->domainService->expects($this->once())->method('getDomain')->with('123')->willReturn($domain); $this->handler->expects($this->once())->method('handle')->with($this->callback( function (ServerRequestInterface $req): bool { Assert::assertEquals($req->getAttribute(ShortUrlInputFilter::DOMAIN), 'something.com'); return true; }, ))->willReturn(new Response()); $this->middleware->process($request, $this->handler); } public static function provideMethods(): iterable { yield 'GET' => ['GET']; yield 'PUT' => ['PUT']; yield 'PATCH' => ['PATCH']; yield 'DELETE' => ['DELETE']; } private function requestWithApiKey(): ServerRequestInterface { return ServerRequestFactory::fromGlobals()->withAttribute(ApiKey::class, $this->apiKey); } }