Skip to content

Commit

Permalink
Issue CollaboraOnline#27: Test access to routes.
Browse files Browse the repository at this point in the history
  • Loading branch information
donquixote committed Sep 13, 2024
1 parent bcc2a26 commit e0a249c
Showing 1 changed file with 251 additions and 0 deletions.
251 changes: 251 additions & 0 deletions tests/src/Functional/AccessTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
<?php

declare(strict_types=1);

namespace Drupal\Tests\collabora_online\Functional;

use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Session\AnonymousUserSession;
use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Drupal\media\Entity\Media;
use Drupal\media\MediaInterface;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\media\Traits\MediaTypeCreationTrait;
use Drupal\Tests\TestFileCreationTrait;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;

/**
* Tests access to collabora routes.
*/
class AccessTest extends BrowserTestBase {

use MediaTypeCreationTrait;
use TestFileCreationTrait;

/**
* {@inheritdoc}
*/
protected static $modules = [
'node',
'media',
'collabora_online',
];

/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';

/**
* Tests access to core paths, to verify that the tests work correctly.
*/
public function testCorePathsAccess(): void {
$this->createMediaType('file', ['id' => 'document']);
$media = $this->createMediaEntity('document');
$media_id = $media->id();

$authenticated = $this->createUser();
$paths = [
// Test the front page as an example that everybody can access.
'/',
// Test an administration page that only admin can see.
'/admin/config',
// Test the user route.
'/user/' . $authenticated->id(),
// Test the core media route for reference.
'/media/' . $media->id() . '/edit',
];
$users = [
'anonymous' => new AnonymousUserSession(),
'authenticated' => $authenticated,
'admin' => $this->createUser(admin: TRUE),
];

// Build a report and assert the full result at once.
// This provides a very complete picture in case the assertion fails.
$this->assertSameReport(
[
'/' => ['anonymous', 'authenticated', 'admin'],
'/admin/config' => ['admin'],
'/user/' . $authenticated->id() => ['authenticated', 'admin'],
"/media/$media_id/edit" => ['admin'],
],
$this->buildAccessReport($paths, $users),
'Users with access to given paths',
);
}

/**
* Tests a scenario when only the administrator has access.
*/
public function testOnlyAdminHasAccess(): void {
$this->createMediaType('file', ['id' => 'document']);
$media = $this->createMediaEntity('document');

$paths = [
'/cool/view/' . $media->id(),
'/cool/edit/' . $media->id(),
];
$users = [
'anonymous' => new AnonymousUserSession(),
'authenticated' => $this->createUser(),
'admin' => $this->createUser(admin: TRUE),
];

// Both routes are only accessible for admin.
$this->assertSameReport(
[
'/cool/view/1' => ['admin'],
'/cool/edit/1' => ['admin'],
],
$this->buildAccessReport($paths, $users),
'Users with access to given paths',
);
}

/**
* Tests a scenario where specific permissions are given to users.
*/
public function testCollaboraMediaPermissions(): void {
$this->createMediaType('file', ['id' => 'document']);
$this->createMediaType('file', ['id' => 'public_wiki']);
$this->createMediaType('file', ['id' => 'public_announcement']);
$this->createMediaType('file', ['id' => 'diary']);
$this->grantPermissions(
Role::load(RoleInterface::ANONYMOUS_ID),
[
'preview public_announcement in collabora',
'preview public_wiki in collabora',
'edit any public_wiki in collabora',
],
);
$diary_keeper = $this->createUser([
'preview diary in collabora',
'edit own diary in collabora'
]);

$media_entities = [
'document' => $this->createMediaEntity('document'),
'wiki' => $this->createMediaEntity('public_wiki'),
'announcement' => $this->createMediaEntity('public_announcement'),
'own diary' => $this->createMediaEntity('diary', ['uid' => $diary_keeper->id()]),
'other diary' => $this->createMediaEntity('diary'),
];

$paths = [];
foreach ($media_entities as $media_key => $media) {
$paths["/cool/view/<$media_key>"] = '/cool/view/' . $media->id();
$paths["/cool/edit/<$media_key>"] = '/cool/edit/' . $media->id();
}
$users = [
'anonymous' => new AnonymousUserSession(),
'authenticated' => $this->createUser(),
'reader' => $this->createUser([
'preview document in collabora',
]),
'editor' => $this->createUser([
'preview document in collabora',
'edit any document in collabora',
]),
// Usually, a user with write access would also be given read access.
'writer' => $this->createUser([
'edit any document in collabora',
]),
'diary keeper' => $diary_keeper,
];

// Both routes are only accessible for admin.
$this->assertSameReport(
[
'/cool/view/<document>' => ['reader', 'editor'],
'/cool/edit/<document>' => ['editor', 'writer'],
'/cool/view/<wiki>' => ['anonymous'],
'/cool/edit/<wiki>' => ['anonymous'],
'/cool/view/<announcement>' => ['anonymous'],
'/cool/edit/<announcement>' => [],
'/cool/view/<own diary>' => ['diary keeper'],
'/cool/edit/<own diary>' => ['diary keeper'],
'/cool/view/<other diary>' => ['diary keeper'],
'/cool/edit/<other diary>' => [],
],
$this->buildAccessReport($paths, $users),
'Users with access to given paths',
);
}

/**
* Builds a report about which users can access a given content.
*
* @param list<string>|array<string, string> $paths
* A list of paths, optionally keyed.
* @param array<string, \Drupal\Core\Session\AccountInterface> $users
* Accounts to test access with.
*
* @return array
* Report to compare against in assertions.
*/
protected function buildAccessReport(array $paths, array $users): array {
$report = [];
foreach ($paths as $path_key => $path) {
if (is_numeric($path_key)) {
$path_key = $path;
}
$report[$path_key] = [];
foreach ($users as $user_key => $user) {
$url = Url::fromUserInput($path);
$access = $url->access($user);
if ($access) {
$report[$path_key][] = $user_key;
}
}
}
return $report;
}

/**
* Creates a media entity with attached file.
*
* @param string $type
* Media type.
* @param array $values
* Values for the media entity.
*
* @return \Drupal\media\MediaInterface
* New media entity.
*/
protected function createMediaEntity(string $type, array $values = []): MediaInterface {
\file_put_contents('public://test.txt', 'Hello test');
$file = File::create([
'uri' => 'public://test.txt',
]);
$file->save();
$values += [
'bundle' => $type,
'field_media_file' => $file->id(),
];
$media = Media::create($values);
$media->save();
return $media;
}

/**
* Asserts two arrays are identical, in a more readable way.
*
* @param array $expected
* Expected array.
* @param array $actual
* Actual array.
* @param string $message
* Message to show if the test fails.
*/
protected function assertSameReport(array $expected, array $actual, string $message): void {
$this->assertSame(
Yaml::encode($expected),
Yaml::encode($actual),
$message,
);
}

}

0 comments on commit e0a249c

Please sign in to comment.