Skip to content
Snippets Groups Projects
Commit 6a28e4bd authored by omkar podey's avatar omkar podey Committed by Adam G-H
Browse files

Issue #3293148 by kunal.sachdev, omkar.podey: Clean up or remove PackageUpdateTest

parent 603cfb23
No related branches found
No related tags found
No related merge requests found
<?php
namespace Drupal\package_manager_test_api;
use Drupal\Core\Block\BlockManagerInterface;
use Drupal\Core\State\StateInterface;
use Drupal\package_manager\Event\PostApplyEvent;
use Drupal\package_manager\Event\PostDestroyEvent;
use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\package_manager\Event\StageEvent;
use Drupal\package_manager\PathLocator;
use Drupal\user\PermissionHandlerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Routing\RouterInterface;
/**
* Defines a service for checking system changes during an update.
*/
class SystemChangeRecorder implements EventSubscriberInterface {
/**
* The path locator service.
*
* @var \Drupal\package_manager\PathLocator
*/
private $pathLocator;
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface
*/
private $state;
/**
* The router service.
*
* @var \Symfony\Component\Routing\RouterInterface
*/
private $router;
/**
* The permission handler service.
*
* @var \Drupal\user\PermissionHandlerInterface
*/
private $permissionHandler;
/**
* The block plugin manager.
*
* @var \Drupal\Core\Block\BlockManagerInterface
*/
private $blockManager;
/**
* Constructs a SystemChangeRecorder object.
*
* @param \Drupal\package_manager\PathLocator $path_locator
* The path locator service.
* @param \Drupal\Core\State\StateInterface $state
* The state service.
* @param \Symfony\Component\Routing\RouterInterface $router
* The router service.
* @param \Drupal\user\PermissionHandlerInterface $permission_handler
* The permission handler service.
* @param \Drupal\Core\Block\BlockManagerInterface $block_manager
* The block plugin manager.
*/
public function __construct(PathLocator $path_locator, StateInterface $state, RouterInterface $router, PermissionHandlerInterface $permission_handler, BlockManagerInterface $block_manager) {
$this->pathLocator = $path_locator;
$this->state = $state;
$this->router = $router;
$this->permissionHandler = $permission_handler;
$this->blockManager = $block_manager;
}
/**
* Records aspects of system state at various points during an update.
*
* @param \Drupal\package_manager\Event\StageEvent $event
* The stage event.
*/
public function recordSystemState(StageEvent $event): void {
// The rest of this method is strongly coupled to updated_module, so if it
// isn't installed, bail out now.
if (!\Drupal::moduleHandler()->moduleExists('updated_module')) {
return;
}
$results = [];
// Call a function in a loaded file to ensure it doesn't get reloaded after
// changes are applied.
$results['return value of existing global function'] = _updated_module_global1();
// Check if a new global function exists after changes are applied.
$results['new global function exists'] = function_exists('_updated_module_global2') ? "exists" : "not exists";
$route_collection = $this->router->getRouteCollection();
// Check if changes to an existing route are picked up.
$results['path of changed route'] = $route_collection->get('updated_module.changed')
->getPath();
// Check if a route removed from the updated module is no longer available.
$results['deleted route exists'] = $route_collection->get('updated_module.deleted') ? 'exists' : 'not exists';
// Check if a route added in the updated module is available.
$results['new route exists'] = $route_collection->get('updated_module.added') ? 'exists' : 'not exists';
$permissions = $this->permissionHandler->getPermissions();
// Check if changes to an existing permission are picked up.
$results['title of changed permission'] = $permissions['changed permission']['title'];
// Check if a permission removed from the updated module is not available.
$results['deleted permission exists'] = array_key_exists('deleted permission', $permissions) ? 'exists' : 'not exists';
// Check if a permission added in the updated module is available.
$results['new permission exists'] = array_key_exists('added permission', $permissions) ? 'exists' : 'not exists';
// Check if changes to an existing service are picked up.
$this->recordServiceValue('updated_module.existing_service', $results);
// Check if a service removed from the updated module is available.
$this->recordServiceValue('updated_module.deleted_service', $results);
// Check if a service added in the updated module is available.
$this->recordServiceValue('updated_module.added_service', $results);
$phase = $event instanceof PreApplyEvent ? 'pre' : 'post';
// Check if changes to a block plugin's definition and implementation are
// picked up.
$this->recordBlockState('updated_module_deleted_block', $results, $phase === 'pre');
$this->recordBlockState('updated_module_updated_block', $results, TRUE);
$this->recordBlockState('updated_module_added_block', $results, $phase === 'post');
// Record the state of a block that was NOT instantiated before the update.
$this->recordBlockState('updated_module_ignored_block', $results, $phase === 'post');
// Check if changes to an existing class are picked up.
$this->recordClassValue('ChangedClass', $results);
// Check if changes to a class that has not been loaded before the update is
// applied, are picked up.
$this->recordClassValue('LoadedAndDeletedClass', $results);
// We can't check AddedClass and DeletedClass in the "pre" phase, because
// class_exists() uses auto-loading, so if we checked these classes in the
// "pre" phase, the results will persist into the "post" phase.
if ($phase === 'post') {
// Check if a class that was removed in the updated module is still
// loaded.
$this->recordClassValue('DeletedClass', $results);
// Check if a class that was added in the updated module is available.
$this->recordClassValue('AddedClass', $results);
}
$this->state->set("system_changes:$phase", $results);
}
/**
* Records the state of a block plugin.
*
* @param string $block_id
* Tbe block plugin ID.
* @param array $results
* The current set of results, passed by reference.
* @param bool $build
* Whether or not to instantiate the block plugin and include its output
* in the results.
*/
private function recordBlockState(string $block_id, array &$results, bool $build): void {
if ($this->blockManager->hasDefinition($block_id)) {
$results["$block_id block exists"] = 'exists';
$plugin_definition = $this->blockManager->getDefinition($block_id);
$results["$block_id block label"] = (string) $plugin_definition['admin_label'];
if ($build) {
$build = $this->blockManager->createInstance($block_id)->build();
$results["$block_id block output"] = (string) $build['#markup'];
}
}
else {
$results["$block_id block exists"] = 'not exists';
}
}
/**
* Checks if a given class exists, and records its 'value' property.
*
* @param string $class_name
* The name of the class to check, not including the namespace.
* @param array $results
* The current set of results, passed by reference.
*/
private function recordClassValue(string $class_name, array &$results): void {
$full_class_name = "Drupal\updated_module\\$class_name";
if (class_exists($full_class_name)) {
$results["$class_name exists"] = 'exists';
$results["value of $class_name"] = $full_class_name::$value;
}
else {
$results["$class_name exists"] = 'not exists';
}
}
/**
* Checks if a given service exists, and records its ->value property.
*
* @param string $service_id
* The ID of the service to check.
* @param array $results
* The current set of results, passed by reference.
*/
private function recordServiceValue(string $service_id, array &$results): void {
if (\Drupal::hasService($service_id)) {
$results["$service_id exists"] = 'exists';
$results["value of $service_id"] = \Drupal::service($service_id)->value;
}
else {
$results["$service_id exists"] = 'not exists';
}
}
/**
* Writes the results of ::recordSystemState() to file.
*
* Build tests do not have access to the Drupal API, so write the results to
* a file so the build test can check them.
*/
public function writeResultsToFile(): void {
$results = [
'pre' => $this->state->get('system_changes:pre'),
'post' => $this->state->get('system_changes:post'),
];
$dir = $this->pathLocator->getProjectRoot();
file_put_contents("$dir/system_changes.json", json_encode($results));
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
return [
PreApplyEvent::class => 'recordSystemState',
PostApplyEvent::class => 'recordSystemState',
PostDestroyEvent::class => 'writeResultsToFile',
];
}
}
......@@ -67,98 +67,6 @@ class PackageUpdateTest extends TemplateProjectTestBase {
// created this file.
// @see \Drupal\updated_module\PostApplySubscriber::postApply()
$this->assertSame('Bravo!', $file_contents['bravo.txt']);
$results = json_decode($file_contents['system_changes.json'], TRUE);
$expected_pre_apply_results = [
'return value of existing global function' => 'pre-update-value',
'new global function exists' => 'not exists',
'path of changed route' => '/updated-module/changed/pre',
'deleted route exists' => 'exists',
'new route exists' => 'not exists',
'title of changed permission' => 'permission',
'deleted permission exists' => 'exists',
'new permission exists' => 'not exists',
'updated_module.existing_service exists' => 'exists',
'value of updated_module.existing_service' => 'Pre-update value',
'updated_module.deleted_service exists' => 'exists',
'value of updated_module.deleted_service' => 'Deleted service, should not exist after update',
'updated_module.added_service exists' => 'not exists',
'updated_module_deleted_block block exists' => 'exists',
'updated_module_deleted_block block label' => 'Deleted block',
'updated_module_deleted_block block output' => 'Goodbye!',
'updated_module_updated_block block exists' => 'exists',
'updated_module_updated_block block label' => '1.0.0',
'updated_module_updated_block block output' => '1.0.0',
'updated_module_added_block block exists' => 'not exists',
// This block is not instantiated until the update is done.
'updated_module_ignored_block block exists' => 'exists',
'updated_module_ignored_block block label' => '1.0.0',
'ChangedClass exists' => 'exists',
'value of ChangedClass' => 'Before Update',
'LoadedAndDeletedClass exists' => 'exists',
'value of LoadedAndDeletedClass' => 'This class will be loaded and then deleted',
];
$this->assertSame($expected_pre_apply_results, $results['pre']);
$expected_post_apply_results = [
// An existing functions will now return a new value.
'return value of existing global function' => 'post-update-value',
// New functions that were added in .module files will be available
// because the post-apply event is dispatched in a new request.
'new global function exists' => 'exists',
// Definitions for existing routes should be updated.
'path of changed route' => '/updated-module/changed/post',
// Routes deleted from the updated module should not be available.
'deleted route exists' => 'not exists',
// Routes added to the updated module should be available.
'new route exists' => 'exists',
// Title of the existing permission should be changed.
'title of changed permission' => 'changed permission',
// Permissions deleted from the updated module should not be available.
'deleted permission exists' => 'not exists',
// Permissions added to the updated module should be available.
'new permission exists' => 'exists',
// The existing generic service should have a new string value.
'updated_module.existing_service exists' => 'exists',
'value of updated_module.existing_service' => 'Post-update value',
// Services deleted from the updated module should not be available.
'updated_module.deleted_service exists' => 'not exists',
// Services added to the updated module should be available and return
// the expected value.
'updated_module.added_service exists' => 'exists',
'value of updated_module.added_service' => 'New service, should not exist before update',
// A block removed from the updated module should not be defined anymore.
'updated_module_deleted_block block exists' => 'not exists',
// A block that was updated should have a changed definition and
// implementation.
'updated_module_updated_block block exists' => 'exists',
'updated_module_updated_block block label' => '1.1.0',
'updated_module_updated_block block output' => '1.1.0',
// A block added to the module should be defined.
'updated_module_added_block block exists' => 'exists',
'updated_module_added_block block label' => 'Added block',
'updated_module_added_block block output' => 'Hello!',
// A block whose definition and implementation were updated, but was NOT
// instantiated before the update, should have an updated definition and
// implementation.
'updated_module_ignored_block block exists' => 'exists',
'updated_module_ignored_block block label' => '1.1.0',
'updated_module_ignored_block block output' => 'I was ignored before the update.',
// Existing class should still be available, and will be outputting its
// new value.
'ChangedClass exists' => 'exists',
'value of ChangedClass' => 'After Update',
// Classes loaded in pre-apply, but deleted from the updated module,
// should be unavailable.
'LoadedAndDeletedClass exists' => 'not exists',
// Classes not loaded before the apply operation and deleted from the updated module
// should not be available.
'DeletedClass exists' => 'not exists',
// Classes added to the updated module should be available.
'AddedClass exists' => 'exists',
'value of AddedClass' => 'This class will be added',
];
$this->assertSame($expected_post_apply_results, $results['post']);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment