Skip to content

Commit

Permalink
Add test for ViewerController.
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronGilMartinez committed Jan 9, 2025
1 parent 2dc47be commit bb0fc06
Showing 1 changed file with 243 additions and 0 deletions.
243 changes: 243 additions & 0 deletions tests/src/Kernel/Controller/ViewerControllerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
<?php

/*
* Copyright the Collabora Online contributors.
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

declare(strict_types=1);

namespace Drupal\Tests\collabora_online\Kernel\Controller;

use Drupal\collabora_online\Cool\CollaboraDiscoveryFetcherInterface;
use Drupal\collabora_online\Cool\CollaboraDiscoveryInterface;
use Drupal\collabora_online\Exception\CollaboraNotAvailableException;
use Drupal\collabora_online\Jwt\JwtTranscoderInterface;
use Drupal\Core\Logger\RfcLogLevel;
use Drupal\Core\Utility\Error;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
* @coversDefaultClass \Drupal\collabora_online\Controller\ViewerController
*/
class ViewerControllerTest extends WopiControllerTestBase {

/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();

// Mock fetcher to get a discovery XML.
$fetcher = $this->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.<br>\n" . Error::DEFAULT_ERROR_MESSAGE,
'level' => RfcLogLevel::WARNING,
],
$name
);
}
}

/**
* Tests requests with a scheme that does not match 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 viewer not 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.<br>\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<string, \Symfony\Component\HttpFoundation\Request>
* 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();
}
}

}

0 comments on commit bb0fc06

Please sign in to comment.