From ae77ba2f9b02ce347a987421f1aca4a145c0ac49 Mon Sep 17 00:00:00 2001 From: AaronGilMartinez Date: Wed, 8 Jan 2025 08:40:55 +0100 Subject: [PATCH] Add test for ViewerController. --- .../Controller/ViewerControllerTest.php | 243 ++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 tests/src/Kernel/Controller/ViewerControllerTest.php diff --git a/tests/src/Kernel/Controller/ViewerControllerTest.php b/tests/src/Kernel/Controller/ViewerControllerTest.php new file mode 100644 index 00000000..c97f392a --- /dev/null +++ b/tests/src/Kernel/Controller/ViewerControllerTest.php @@ -0,0 +1,243 @@ +createMock(CollaboraDiscoveryFetcherInterface::class); + $file = dirname(__DIR__, 3) . '/fixtures/discovery.mimetypes.xml'; + $xml = file_get_contents($file); + $fetcher->method('getDiscoveryXml')->willReturn($xml); + $this->container->set(CollaboraDiscoveryFetcherInterface::class, $fetcher); + + $this->user = $this->createUser([ + 'access content', + 'preview document in collabora', + 'edit any document in collabora', + ]); + + $this->setCurrentUser($this->user); + } + + /** + * Tests successful requests. + * + * @covers ::editor + */ + public function testEditorSuccess(): void { + foreach ($this->createRequests() as $name => $request) { + $this->assertResponseOk($request, $name); + } + } + + /** + * Tests requests with Collabora unavailable. + * + * @covers ::editor + */ + public function testEditorCollaboraUnavailable(): void { + // Restore service to force fail. + $fetcher = $this->createMock(CollaboraDiscoveryFetcherInterface::class); + $this->container->set(CollaboraDiscoveryFetcherInterface::class, $fetcher); + + foreach ($this->createRequests() as $name => $request) { + $this->assertBadRequestResponse( + 'The Collabora Online editor/viewer is not available.', + $request, + [ + 'message' => "Collabora Online is not available.
\n" . Error::DEFAULT_ERROR_MESSAGE, + 'level' => RfcLogLevel::WARNING, + ], + $name + ); + } + } + + /** + * Tests requests with a scheme not matching the Collabora client URL. + * + * @covers ::editor + */ + public function testEditorMismatchScheme(): void { + $wopi_url = \Drupal::service(CollaboraDiscoveryInterface::class)->getWopiClientURL(); + + foreach ($this->createRequests(scheme: 'https') as $name => $request) { + $this->assertBadRequestResponse( + 'Viewer error: Protocol mismatch.', + $request, + [ + 'message' => "The current request uses 'https' url scheme, but the Collabora client url is '$wopi_url'.", + 'level' => RfcLogLevel::ERROR, + ], + $name + ); + } + } + + /** + * Tests requests with a no viewer available. + * + * @covers ::editor + */ + public function testEditorNoViewer(): void { + // Mock transcoder to force fail. + $transcoder = $this->createMock(jwtTranscoderInterface::class); + $transcoder->method('encode')->willThrowException(new CollaboraNotAvailableException()); + $this->container->set(jwtTranscoderInterface::class, $transcoder); + $this->expectException(CollaboraNotAvailableException::class); + + foreach ($this->createRequests() as $name => $request) { + $this->assertBadRequestResponse( + 'The Collabora Online editor/viewer is not available.', + $request, + [ + 'message' => "Cannot show the viewer/editor.
\n" . Error::DEFAULT_ERROR_MESSAGE, + 'level' => RfcLogLevel::WARNING, + ], + $name + ); + } + } + + /** + * {@inheritDoc} + * + * @param int|null $media_id + * Media entity id, if different from the default. + * @param int|null $user_id + * User id, if different from the default. + * @param array $token_payload + * Explicit token payload values. + * This can be used to cause a bad token. + * @param string $scheme + * Scheme used for the request. + * + * @return array + * Requests keyed by a distinguishable name. + */ + protected function createRequests(?int $media_id = NULL, ?int $user_id = NULL, array $token_payload = [], $scheme = 'http'): array { + return [ + 'view' => $this->createRequest(scheme: $scheme), + 'view_write' => $this->createRequest(scheme: $scheme, write: TRUE), + 'edit' => $this->createRequest('edit', $scheme), + 'edit_write' => $this->createRequest('edit', scheme: $scheme, write: TRUE), + ]; + } + + /** + * Creates a view/edit request. + * + * @param string $action + * View or edit the media. + * @param string $scheme + * Scheme used for the request. + * @param int|null $media_id + * Media entity id, if different from the default. + * @param int|null $user_id + * User id, if different from the default. + * @param bool $write + * TRUE if write access is requested. + * @param array $token_payload + * Explicit token payload values. + * This can be used to cause a bad token. + * + * @return \Symfony\Component\HttpFoundation\Request + * The request. + */ + protected function createRequest( + string $action = 'view', + string $scheme = 'http', + ?int $media_id = NULL, + ?int $user_id = NULL, + bool $write = FALSE, + array $token_payload = [], + ): Request { + $media_id ??= (int) $this->media->id(); + $user_id ??= (int) $this->user->id(); + $uri = "$scheme://localhost/cool/$action/$media_id"; + $token = $this->createAccessToken($media_id, $user_id, $write, $token_payload); + $parameters = [ + 'access_token' => $token, + 'access_token_ttl' => '0', + ]; + return Request::create($uri, 'GET', $parameters); + } + + /** + * Asserts an successful response given a request. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request to perform. + * @param string $message + * Message to distinguish this from other assertions. + */ + protected function assertResponseOk(Request $request, string $message = ''): void { + $response = $this->handleRequest($request); + + $this->assertEquals(Response::HTTP_OK, $response->getStatusCode(), $message); + $this->assertStringContainsString('iframe', $response->getContent(), $message); + $this->assertEquals('', $response->headers->get('Content-Type'), $message); + } + + /** + * Asserts an bad request response given a request. + * + * @param string $expected_content + * The expected content. + * @param \Symfony\Component\HttpFoundation\Request $request + * The request to perform. + * @param array $expected_log + * The expected log entry. + * @param string $message + * Message to distinguish this from other assertions. + */ + protected function assertBadRequestResponse(string $expected_content, Request $request, array $expected_log = [], string $message = ''): void { + $this->assertResponse( + Response::HTTP_BAD_REQUEST, + $expected_content, + 'text/plain', + $request, + $message, + ); + + if ($expected_log) { + $this->assertTrue( + $this->logger->hasRecord($expected_log['message'], $expected_log['level'] ?? NULL), + sprintf('The logger does not contain a record like: "%s".', $expected_log['message']) + ); + $this->logger->reset(); + } + } + +}