diff --git a/package_manager/tests/modules/package_manager_bypass/package_manager_bypass.services.yml b/package_manager/tests/modules/package_manager_bypass/package_manager_bypass.services.yml new file mode 100644 index 0000000000000000000000000000000000000000..da76b850debb14aebd68e160e3bd60f1fab20188 --- /dev/null +++ b/package_manager/tests/modules/package_manager_bypass/package_manager_bypass.services.yml @@ -0,0 +1,9 @@ +services: + package_manager_bypass.beginner: + class: Drupal\package_manager_bypass\Beginner + arguments: ['@state', '@package_manager_bypass.beginner.inner' ] + decorates: 'package_manager.beginner' + package_manager_bypass.committer: + class: Drupal\package_manager_bypass\Committer + arguments: [ '@state', '@package_manager_bypass.committer.inner' ] + decorates: 'package_manager.committer' diff --git a/package_manager/tests/modules/package_manager_bypass/src/Beginner.php b/package_manager/tests/modules/package_manager_bypass/src/Beginner.php index 5894f60e7bb101842ac2910a4dac868e0c05fef3..5c980230bc6ce1c0d0beabe02b399eb5ee91cf38 100644 --- a/package_manager/tests/modules/package_manager_bypass/src/Beginner.php +++ b/package_manager/tests/modules/package_manager_bypass/src/Beginner.php @@ -4,6 +4,7 @@ declare(strict_types = 1); namespace Drupal\package_manager_bypass; +use Drupal\Core\State\StateInterface; use Drupal\fixture_manipulator\StageFixtureManipulator; use PhpTuf\ComposerStager\Domain\Core\Beginner\BeginnerInterface; use PhpTuf\ComposerStager\Domain\Service\ProcessOutputCallback\ProcessOutputCallbackInterface; @@ -12,10 +13,30 @@ use PhpTuf\ComposerStager\Domain\Value\Path\PathInterface; use PhpTuf\ComposerStager\Domain\Value\PathList\PathListInterface; /** - * Defines an update beginner which doesn't do anything. + * Defines a service that decorates the Composer Stager beginner service. */ class Beginner extends BypassedStagerServiceBase implements BeginnerInterface { + /** + * The decorated service. + * + * @var \PhpTuf\ComposerStager\Domain\Core\Beginner\BeginnerInterface + */ + private $inner; + + /** + * Constructs a Beginner object. + * + * @param \Drupal\Core\State\StateInterface $state + * The state service. + * @param \PhpTuf\ComposerStager\Domain\Core\Beginner\BeginnerInterface $inner + * The decorated beginner service. + */ + public function __construct(StateInterface $state, BeginnerInterface $inner) { + $this->state = $state; + $this->inner = $inner; + } + /** * A reference to the stage fixture manipulator, if any. * @@ -31,7 +52,7 @@ class Beginner extends BypassedStagerServiceBase implements BeginnerInterface { */ public function begin(PathInterface $activeDir, PathInterface $stagingDir, ?PathListInterface $exclusions = NULL, ?ProcessOutputCallbackInterface $callback = NULL, ?int $timeout = ProcessRunnerInterface::DEFAULT_TIMEOUT): void { $this->saveInvocationArguments($activeDir, $stagingDir, $exclusions, $timeout); - $this->copyFixtureFilesTo($stagingDir); + $this->inner->begin($activeDir, $stagingDir, $exclusions, $callback, $timeout); /** @var \Drupal\fixture_manipulator\StageFixtureManipulator|null $stageManipulator */ $stageManipulator = $this->state->get(__CLASS__ . '-stage-manipulator', NULL); diff --git a/package_manager/tests/modules/package_manager_bypass/src/BypassedStagerServiceBase.php b/package_manager/tests/modules/package_manager_bypass/src/BypassedStagerServiceBase.php index 06106bc3bb3c007eaaef91a09a1330ce5b0a2694..cb779b2770a57739bed9946cb76e923844f50ad0 100644 --- a/package_manager/tests/modules/package_manager_bypass/src/BypassedStagerServiceBase.php +++ b/package_manager/tests/modules/package_manager_bypass/src/BypassedStagerServiceBase.php @@ -4,10 +4,6 @@ declare(strict_types = 1); namespace Drupal\package_manager_bypass; -use Drupal\Core\State\StateInterface; -use PhpTuf\ComposerStager\Domain\Value\Path\PathInterface; -use Symfony\Component\Filesystem\Filesystem; - /** * Records information about method invocations. * @@ -24,59 +20,6 @@ abstract class BypassedStagerServiceBase { */ protected $state; - /** - * The Symfony file system service. - * - * @var \Symfony\Component\Filesystem\Filesystem - */ - protected $fileSystem; - - /** - * Constructs an InvocationRecorderBase object. - * - * @param \Drupal\Core\State\StateInterface $state - * The state service. - * @param \Symfony\Component\Filesystem\Filesystem $file_system - * The Symfony file system service. - */ - public function __construct(StateInterface $state, Filesystem $file_system) { - $this->state = $state; - $this->fileSystem = $file_system; - } - - /** - * Sets a path to be mirrored into a destination by the main class method. - * - * @param string|null $path - * A path to mirror into a destination directory when the main class method - * is called, or NULL to disable. - * - * @see ::copyFixtureFilesTo() - */ - public static function setFixturePath(?string $path): void { - \Drupal::state()->set(static::class . ' fixture', $path); - } - - /** - * If a fixture path has been set, mirrors it to the given path. - * - * Files in the destination directory but not in the source directory will - * not be deleted. - * - * @param \PhpTuf\ComposerStager\Domain\Value\Path\PathInterface $destination - * The path to which the fixture files should be mirrored. - */ - protected function copyFixtureFilesTo(PathInterface $destination): void { - $fixture_path = $this->state->get(static::class . ' fixture'); - - if ($fixture_path && is_dir($fixture_path)) { - $this->fileSystem->mirror($fixture_path, $destination->resolve(), NULL, [ - 'override' => TRUE, - 'delete' => FALSE, - ]); - } - } - /** * Returns the arguments from every invocation of the main class method. * diff --git a/package_manager/tests/modules/package_manager_bypass/src/Committer.php b/package_manager/tests/modules/package_manager_bypass/src/Committer.php index 06df4d0d399c4116f29b37d31a991757a5e53fc0..5c3ea425193a8fa044fe48524b38af15203bcf4b 100644 --- a/package_manager/tests/modules/package_manager_bypass/src/Committer.php +++ b/package_manager/tests/modules/package_manager_bypass/src/Committer.php @@ -4,6 +4,7 @@ declare(strict_types = 1); namespace Drupal\package_manager_bypass; +use Drupal\Core\State\StateInterface; use PhpTuf\ComposerStager\Domain\Core\Committer\CommitterInterface; use PhpTuf\ComposerStager\Domain\Service\ProcessOutputCallback\ProcessOutputCallbackInterface; use PhpTuf\ComposerStager\Domain\Service\ProcessRunner\ProcessRunnerInterface; @@ -11,10 +12,30 @@ use PhpTuf\ComposerStager\Domain\Value\Path\PathInterface; use PhpTuf\ComposerStager\Domain\Value\PathList\PathListInterface; /** - * Defines an update committer which doesn't do any actual committing. + * Defines a service that decorates the Composer Stager committer service. */ class Committer extends BypassedStagerServiceBase implements CommitterInterface { + /** + * The decorated service. + * + * @var \PhpTuf\ComposerStager\Domain\Core\Committer\CommitterInterface + */ + private $inner; + + /** + * Constructs an Committer object. + * + * @param \Drupal\Core\State\StateInterface $state + * The state service. + * @param \PhpTuf\ComposerStager\Domain\Core\Committer\CommitterInterface $inner + * The decorated committer service. + */ + public function __construct(StateInterface $state, CommitterInterface $inner) { + $this->state = $state; + $this->inner = $inner; + } + /** * {@inheritdoc} */ @@ -23,17 +44,7 @@ class Committer extends BypassedStagerServiceBase implements CommitterInterface if ($exception = $this->state->get(static::class . '-exception')) { throw $exception; } - $this->copyFixtureFilesTo($activeDir); - } - - /** - * {@inheritdoc} - */ - public static function setFixturePath(?string $path): void { - // We haven't yet encountered a situation where we need the committer to - // copy fixture files to the active directory, but when we do, go ahead and - // remove this entire method. - throw new \BadMethodCallException('This is not implemented yet.'); + $this->inner->commit($stagingDir, $activeDir, $exclusions, $callback, $timeout); } /** diff --git a/package_manager/tests/modules/package_manager_bypass/src/PackageManagerBypassServiceProvider.php b/package_manager/tests/modules/package_manager_bypass/src/PackageManagerBypassServiceProvider.php index f0edab958d5a76a8e8e27e88576bced59f105533..171604c0b56a7fff8b037cc2c027aaca7bcae6a3 100644 --- a/package_manager/tests/modules/package_manager_bypass/src/PackageManagerBypassServiceProvider.php +++ b/package_manager/tests/modules/package_manager_bypass/src/PackageManagerBypassServiceProvider.php @@ -8,7 +8,6 @@ use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ServiceProviderBase; use Drupal\Core\Site\Settings; use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\Filesystem\Filesystem; /** * Defines services to bypass Package Manager's core functionality. @@ -22,19 +21,8 @@ class PackageManagerBypassServiceProvider extends ServiceProviderBase { parent::alter($container); $state = new Reference('state'); - $arguments = [ - $state, - new Reference(Filesystem::class), - ]; if (Settings::get('package_manager_bypass_composer_stager', TRUE)) { - $services = [ - 'package_manager.beginner' => Beginner::class, - 'package_manager.stager' => Stager::class, - 'package_manager.committer' => Committer::class, - ]; - foreach ($services as $id => $class) { - $container->getDefinition($id)->setClass($class)->setArguments($arguments); - } + $container->getDefinition('package_manager.stager')->setClass(Stager::class)->setArguments([$state]); } $definition = $container->getDefinition('package_manager.path_locator') diff --git a/package_manager/tests/modules/package_manager_bypass/src/Stager.php b/package_manager/tests/modules/package_manager_bypass/src/Stager.php index 1e728500227c54c3c4076440eba060a9c8ddfc97..a5420693d836099f988778ae13cd701969a97bd8 100644 --- a/package_manager/tests/modules/package_manager_bypass/src/Stager.php +++ b/package_manager/tests/modules/package_manager_bypass/src/Stager.php @@ -5,6 +5,7 @@ declare(strict_types = 1); namespace Drupal\package_manager_bypass; use Composer\Json\JsonFile; +use Drupal\Core\State\StateInterface; use PhpTuf\ComposerStager\Domain\Core\Stager\StagerInterface; use PhpTuf\ComposerStager\Domain\Service\ProcessOutputCallback\ProcessOutputCallbackInterface; use PhpTuf\ComposerStager\Domain\Service\ProcessRunner\ProcessRunnerInterface; @@ -15,12 +16,21 @@ use PhpTuf\ComposerStager\Domain\Value\Path\PathInterface; */ class Stager extends BypassedStagerServiceBase implements StagerInterface { + /** + * Constructs a Stager object. + * + * @param \Drupal\Core\State\StateInterface $state + * The state service. + */ + public function __construct(StateInterface $state) { + $this->state = $state; + } + /** * {@inheritdoc} */ public function stage(array $composerCommand, PathInterface $activeDir, PathInterface $stagingDir, ?ProcessOutputCallbackInterface $callback = NULL, ?int $timeout = ProcessRunnerInterface::DEFAULT_TIMEOUT): void { $this->saveInvocationArguments($composerCommand, $stagingDir, $timeout); - $this->copyFixtureFilesTo($stagingDir); // If desired, simulate a change to the lock file (e.g., as a result of // running `composer update`). diff --git a/package_manager/tests/src/Kernel/FixtureManipulatorTest.php b/package_manager/tests/src/Kernel/FixtureManipulatorTest.php index d742bf8f6c3e3a6157190f6fc5782bc9e7e58335..cb1f734093cd4d032b2342f48c40d01e2005b565 100644 --- a/package_manager/tests/src/Kernel/FixtureManipulatorTest.php +++ b/package_manager/tests/src/Kernel/FixtureManipulatorTest.php @@ -379,13 +379,14 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase { // test project, it's located inside the project root. $this->assertTrue(chmod($path_locator->getVendorDirectory(), 0777)); $this->assertTrue(chmod($path_locator->getProjectRoot(), 0777)); + $stage_path = $path_locator->getStagingRoot() . '/stage' . $this->databasePrefix; // Simulate a stage beginning, which would commit the changes. // @see \Drupal\package_manager_bypass\Beginner::begin() $path_factory = new PathFactory(); $this->container->get('package_manager.beginner')->begin( $path_factory->create($path_locator->getProjectRoot()), - $path_factory->create($path_locator->getStagingRoot()), + $path_factory->create($stage_path), ); } diff --git a/package_manager/tests/src/Kernel/PackageManagerKernelTestBase.php b/package_manager/tests/src/Kernel/PackageManagerKernelTestBase.php index 63929a6ee8dbf124706423c2fb1f2f6c98611f23..09d891a486046fe0f6eb96d995bcba04b69de929 100644 --- a/package_manager/tests/src/Kernel/PackageManagerKernelTestBase.php +++ b/package_manager/tests/src/Kernel/PackageManagerKernelTestBase.php @@ -15,7 +15,6 @@ use Drupal\package_manager\UnusedConfigFactory; use Drupal\package_manager\Validator\DiskSpaceValidator; use Drupal\package_manager\Exception\StageValidationException; use Drupal\package_manager\Stage; -use Drupal\package_manager_bypass\Beginner; use Drupal\Tests\package_manager\Traits\AssertPreconditionsTrait; use Drupal\Tests\package_manager\Traits\FixtureUtilityTrait; use Drupal\Tests\package_manager\Traits\ValidationTestTrait; @@ -261,10 +260,6 @@ abstract class PackageManagerKernelTestBase extends KernelTestBase { $path_locator = $this->container->get('package_manager.path_locator'); $path_locator->setPaths($active_dir, $active_dir . '/vendor', '', $staging_root); - // Ensure the active directory will be copied into the test project's stage - // directory. - Beginner::setFixturePath($active_dir); - // This validator will persist through container rebuilds. // @see ::register() $validator = new TestDiskSpaceValidator( diff --git a/package_manager/tests/src/Kernel/StageOwnershipTest.php b/package_manager/tests/src/Kernel/StageOwnershipTest.php index 83b3c50e408080bcebc2280e0837e616d805285d..333f8655c837c388d4915c2f222e52bb47bb6fc7 100644 --- a/package_manager/tests/src/Kernel/StageOwnershipTest.php +++ b/package_manager/tests/src/Kernel/StageOwnershipTest.php @@ -10,7 +10,6 @@ use Drupal\package_manager\Event\PostDestroyEvent; use Drupal\package_manager\Event\PreCreateEvent; use Drupal\package_manager\Exception\StageException; use Drupal\package_manager\Exception\StageOwnershipException; -use Drupal\package_manager_bypass\Stager; use Drupal\package_manager_test_validation\EventSubscriber\TestSubscriber; use Drupal\Tests\user\Traits\UserCreationTrait; use ColinODell\PsrTestLogger\TestLogger; @@ -198,12 +197,6 @@ class StageOwnershipTest extends PackageManagerKernelTestBase { 'postApply' => [], 'destroy' => [], ]; - // Since we deliberately don't call create() on the stages we create as - // we loop through the life cycle methods, ensure that the active directory - // is mirrored into the stage directory when a package is required. - $active_dir = $this->container->get('package_manager.path_locator') - ->getProjectRoot(); - Stager::setFixturePath($active_dir); foreach ($callbacks as $method => $arguments) { // Create a new stage instance for each method. $this->createStage()->claim($stage_id)->$method(...$arguments); diff --git a/package_manager/tests/src/Kernel/StageTest.php b/package_manager/tests/src/Kernel/StageTest.php index 78a570c235f9219ac0267c292709d4ee160a3358..01e4178ebf75ad508b96272851886f85c3de4cf7 100644 --- a/package_manager/tests/src/Kernel/StageTest.php +++ b/package_manager/tests/src/Kernel/StageTest.php @@ -17,7 +17,6 @@ use Drupal\package_manager\Event\StageEvent; use Drupal\package_manager\Exception\ApplyFailedException; use Drupal\package_manager\Exception\StageException; use Drupal\package_manager\Stage; -use Drupal\package_manager_bypass\Beginner; use Drupal\package_manager_bypass\Committer; use PhpTuf\ComposerStager\Domain\Exception\InvalidArgumentException; use PhpTuf\ComposerStager\Domain\Exception\PreconditionException; @@ -58,9 +57,6 @@ class StageTest extends PackageManagerKernelTestBase { $validator = $this->container->get('package_manager.validator.file_system'); $this->container->get('event_dispatcher')->removeSubscriber($validator); - // Don't mirror the active directory from the test project. - Beginner::setFixturePath(NULL); - /** @var \Drupal\package_manager_bypass\PathLocator $path_locator */ $path_locator = $this->container->get('package_manager.path_locator'); @@ -104,54 +100,55 @@ class StageTest extends PackageManagerKernelTestBase { * The test cases. */ public function providerDestroyDuringApply(): array { + $error_message_while_being_applied = 'Cannot destroy the stage directory while it is being applied to the active directory.'; return [ 'force destroy on pre-apply, fresh' => [ PreApplyEvent::class, TRUE, 1, - TRUE, + $error_message_while_being_applied, ], 'destroy on pre-apply, fresh' => [ PreApplyEvent::class, FALSE, 1, - TRUE, + $error_message_while_being_applied, ], 'force destroy on pre-apply, stale' => [ PreApplyEvent::class, TRUE, 7200, - FALSE, + 'Stage directory does not exist', ], 'destroy on pre-apply, stale' => [ PreApplyEvent::class, FALSE, 7200, - FALSE, + 'Stage directory does not exist', ], 'force destroy on post-apply, fresh' => [ PostApplyEvent::class, TRUE, 1, - TRUE, + $error_message_while_being_applied, ], 'destroy on post-apply, fresh' => [ PostApplyEvent::class, FALSE, 1, - TRUE, + $error_message_while_being_applied, ], 'force destroy on post-apply, stale' => [ PostApplyEvent::class, TRUE, 7200, - FALSE, + NULL, ], 'destroy on post-apply, stale' => [ PostApplyEvent::class, FALSE, 7200, - FALSE, + NULL, ], ]; } @@ -166,12 +163,13 @@ class StageTest extends PackageManagerKernelTestBase { * @param int $time_offset * How many simulated seconds should have elapsed between the PreApplyEvent * being dispatched and the attempt to destroy the stage. - * @param bool $expect_exception - * Whether or not destroying the stage will raise an exception. + * @param string|null $expected_exception_message + * The expected exception message string if an exception is expected, or + * NULL if no exception message was expected. * * @dataProvider providerDestroyDuringApply */ - public function testDestroyDuringApply(string $event_class, bool $force, int $time_offset, bool $expect_exception): void { + public function testDestroyDuringApply(string $event_class, bool $force, int $time_offset, ?string $expected_exception_message): void { $listener = function (StageEvent $event) use ($force, $time_offset): void { // Simulate that a certain amount of time has passed since we started // applying staged changes. After a point, it should be possible to @@ -183,15 +181,22 @@ class StageTest extends PackageManagerKernelTestBase { // simulate an attempt to destroy the stage while it's being applied, for // testing purposes. $event->getStage()->destroy($force); + // @see \PhpTuf\ComposerStager\Infrastructure\Service\Precondition\StagingDirDoesNotExist + Committer::setException( + new PreconditionException( + $this->prophesize(PreconditionInterface::class)->reveal(), + 'Stage directory does not exist', + ) + ); }; $this->addEventTestListener($listener, $event_class, 0); $stage = $this->createStage(); $stage->create(); $stage->require(['ext-json:*']); - if ($expect_exception) { + if ($expected_exception_message) { $this->expectException(StageException::class); - $this->expectExceptionMessage('Cannot destroy the stage directory while it is being applied to the active directory.'); + $this->expectExceptionMessage($expected_exception_message); } $stage->apply(); diff --git a/tests/src/Functional/AutomaticUpdatesFunctionalTestBase.php b/tests/src/Functional/AutomaticUpdatesFunctionalTestBase.php index f1869aa91c676fe3f2677d1a0b9fc352d5836a36..c123e14354bf10186d158334f2430279672bf85e 100644 --- a/tests/src/Functional/AutomaticUpdatesFunctionalTestBase.php +++ b/tests/src/Functional/AutomaticUpdatesFunctionalTestBase.php @@ -6,7 +6,6 @@ namespace Drupal\Tests\automatic_updates\Functional; use Drupal\automatic_updates\CronUpdater; use Drupal\Core\Site\Settings; -use Drupal\package_manager_bypass\Beginner; use Drupal\Tests\BrowserTestBase; use Drupal\Tests\package_manager\Traits\AssertPreconditionsTrait; use Drupal\Tests\package_manager\Traits\FixtureUtilityTrait; @@ -206,7 +205,6 @@ abstract class AutomaticUpdatesFunctionalTestBase extends BrowserTestBase { // unique for each test run. This will enable changing files in the // directory and not affect other tests. $active_dir = $this->copyFixtureToTempDirectory($fixture_directory); - Beginner::setFixturePath($active_dir); $this->container->get('package_manager.path_locator') ->setPaths($active_dir, $active_dir . '/vendor', '', NULL); }