forked from CollaboraOnline/collabora-drupal
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Issue CollaboraOnline#27: Test access to routes.
- Loading branch information
1 parent
bcc2a26
commit e0a249c
Showing
1 changed file
with
251 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
); | ||
} | ||
|
||
} |