Skip to content
Snippets Groups Projects
Commit b1abe1f5 authored by Adam G-H's avatar Adam G-H
Browse files

Issue #3279108 by phenaproxima: Merge package_manager_test_fixture into package_manager_bypass

parent 7871102f
No related branches found
No related tags found
No related merge requests found
Showing
with 252 additions and 228 deletions
......@@ -51,7 +51,7 @@ class ExtensionUpdater extends Stage {
$this->tempStore->set(static::TEMPSTORE_METADATA_KEY, [
'packages' => $package_versions,
]);
return parent::create();
return $this->create();
}
/**
......
......@@ -16,57 +16,60 @@ use Drupal\Tests\automatic_updates_extensions\Kernel\AutomaticUpdatesExtensionsK
*/
class PackagesInstalledWithComposerValidatorTest extends AutomaticUpdatesExtensionsKernelTestBase {
/**
* The active directory in the virtual file system.
*
* @var string
*/
private $activeDir;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
// In this test, we don't focus on validating that the updated projects are
// secure and supported. Therefore, we need to disable the update release
// validator that validates updated projects are secure and supported.
// In this test, we don't care whether the updated projects are secure and
// supported.
$this->disableValidators[] = 'automatic_updates_extensions.validator.target_release';
// In this test, we don't focus on validating that the updated projects are
// only themes or modules. Therefore, we need to disable the update packages
// type validator.
// We also don't care if the updated projects are themes and modules only.
$this->disableValidators[] = 'automatic_updates_extensions.validator.packages_type';
parent::setUp();
$this->activeDir = $this->container->get('package_manager.path_locator')
$active_dir = $this->container->get('package_manager.path_locator')
->getProjectRoot();
$installed = __DIR__ . '/../../../fixtures/packages_installed_with_composer_validator/active.installed.json';
$this->assertFileIsReadable($installed);
copy($installed, $active_dir . '/vendor/composer/installed.json');
}
/**
* Data provider for testPreCreateException().
*
* @return array
* @return array[]
* Test cases for testPreCreateException().
*/
public function providerPreCreateException(): array {
$summary = t('Automatic Updates can only update projects that were installed via Composer. The following packages are not installed through composer:');
return [
'module not installed via composer' => [
'module not installed via Composer' => [
[
'new_module' => '9.8.0',
],
[ValidationResult::createError(['new_module'], t('Automatic Updates can only update projects that were installed via Composer. The following packages are not installed through composer:'))],
[
ValidationResult::createError(['new_module'], $summary),
],
],
'theme not installed via composer' => [
'theme not installed via Composer' => [
[
'new_theme' => '9.8.0',
],
[ValidationResult::createError(['new_theme'], t('Automatic Updates can only update projects that were installed via Composer. The following packages are not installed through composer:'))],
[
ValidationResult::createError(['new_theme'], $summary),
],
],
'profile not installed via composer' => [
'profile not installed via Composer' => [
[
'new_profile' => '9.8.0',
],
[ValidationResult::createError(['new_profile'], t('Automatic Updates can only update projects that were installed via Composer. The following packages are not installed through composer:'))],
[
ValidationResult::createError(['new_profile'], $summary),
],
],
'module_theme_profile_dependency_not_installed_via_composer' => [
'module, theme, profile, and library not installed via Composer' => [
[
'new_module' => '9.8.0',
'new_theme' => '9.8.0',
......@@ -74,12 +77,10 @@ class PackagesInstalledWithComposerValidatorTest extends AutomaticUpdatesExtensi
'new_dependency' => '9.8.0',
],
[
ValidationResult::createError(
['new_module', 'new_theme', 'new_profile', 'new_dependency'],
t('Automatic Updates can only update projects that were installed via Composer. The following packages are not installed through composer:')),
ValidationResult::createError(['new_module', 'new_theme', 'new_profile', 'new_dependency'], $summary),
],
],
'module_theme_profile_installed_via_composer' => [
'module, theme, and profile installed via Composer' => [
[
'existing_module' => '9.8.1',
'existing_theme' => '9.8.1',
......@@ -87,18 +88,20 @@ class PackagesInstalledWithComposerValidatorTest extends AutomaticUpdatesExtensi
],
[],
],
'existing module installed and new module not installed via composer' => [
'existing module installed and new module not installed via Composer' => [
[
'existing_module' => '9.8.1',
'new_module' => '9.8.0',
],
[ValidationResult::createError(['new_module'], t('Automatic Updates can only update projects that were installed via Composer. The following packages are not installed through composer:'))],
[
ValidationResult::createError(['new_module'], $summary),
],
],
];
}
/**
* Tests the packages installed with composer during pre-create.
* Tests the packages installed with Composer during pre-create.
*
* @param array $projects
* The projects to install.
......@@ -108,11 +111,6 @@ class PackagesInstalledWithComposerValidatorTest extends AutomaticUpdatesExtensi
* @dataProvider providerPreCreateException
*/
public function testPreCreateException(array $projects, array $expected_results): void {
// Path of `active.installed.json` file. It will be used as the virtual
// project's active `vendor/composer/installed.json` file.
$active_installed = __DIR__ . '/../../../fixtures/packages_installed_with_composer_validator/active.installed.json';
$this->assertFileIsReadable($active_installed);
copy($active_installed, "$this->activeDir/vendor/composer/installed.json");
$this->assertUpdateResults($projects, $expected_results, PreCreateEvent::class);
}
......@@ -123,32 +121,38 @@ class PackagesInstalledWithComposerValidatorTest extends AutomaticUpdatesExtensi
* Test cases for testPreApplyException().
*/
public function providerPreApplyException(): array {
$summary = t('Automatic Updates can only update projects that were installed via Composer. The following packages are not installed through composer:');
$fixtures_folder = __DIR__ . '/../../../fixtures/packages_installed_with_composer_validator';
return [
'module not installed via composer' => [
'module not installed via Composer' => [
"$fixtures_folder/module_not_installed.staged.installed.json",
[ValidationResult::createError(['new_module'], t('Automatic Updates can only update projects that were installed via Composer. The following packages are not installed through composer:'))],
[
ValidationResult::createError(['new_module'], $summary),
],
],
'theme not installed via composer' => [
'theme not installed via Composer' => [
"$fixtures_folder/theme_not_installed.staged.installed.json",
[ValidationResult::createError(['new_theme'], t('Automatic Updates can only update projects that were installed via Composer. The following packages are not installed through composer:'))],
[
ValidationResult::createError(['new_theme'], $summary),
],
],
'profile not installed via composer' => [
'profile not installed via Composer' => [
"$fixtures_folder/profile_not_installed.staged.installed.json",
[ValidationResult::createError(['new_profile'], t('Automatic Updates can only update projects that were installed via Composer. The following packages are not installed through composer:'))],
[
ValidationResult::createError(['new_profile'], $summary),
],
],
// Dependency drupal/new_dependency of type 'drupal-library' will not show
// up in the error because it is not one of the covered types
// ('drupal-module', 'drupal-theme' or 'drupal-profile'). Module
// new_module1 will also not show up as it's name doesn't start with
// 'drupal/'.
// The `drupal/new_dependency` package won't show up in the error because
// its type is `drupal-library`, and the validator only considers the
// `drupal-module`, `drupal-theme`, and `drupal-profile` package types.
// The `not-drupal/new_module1` package won't show up either, even though
// its type is `drupal-module`, because it doesn't start with `drupal/`.
// @see \Drupal\automatic_updates_extensions\Validator\PackagesInstalledWithComposerValidator
'module_theme_profile_dependency_not_installed_via_composer' => [
'module, theme, and profile not installed via Composer' => [
"$fixtures_folder/module_theme_profile_dependency_not_installed.staged.installed.json",
[
ValidationResult::createError(
['new_module', 'new_theme', 'new_profile'],
t('Automatic Updates can only update projects that were installed via Composer. The following packages are not installed through composer:')),
ValidationResult::createError(['new_module', 'new_theme', 'new_profile'], $summary),
],
],
];
......@@ -166,18 +170,14 @@ class PackagesInstalledWithComposerValidatorTest extends AutomaticUpdatesExtensi
* @dataProvider providerPreApplyException
*/
public function testPreApplyException(string $staged_installed, array $expected_results): void {
// Path of `active.installed.json` file. It will be used as the virtual
// project's active `vendor/composer/installed.json` file.
$active_installed = __DIR__ . '/../../../fixtures/packages_installed_with_composer_validator/active.installed.json';
$this->assertFileIsReadable($active_installed);
$this->assertFileIsReadable($staged_installed);
copy($active_installed, "$this->activeDir/vendor/composer/installed.json");
$listener = function (PreApplyEvent $event) use ($staged_installed): void {
$stage_dir = $event->getStage()->getStageDirectory();
copy($staged_installed, $stage_dir . "/vendor/composer/installed.json");
};
$this->container->get('event_dispatcher')->addListener(PreApplyEvent::class, $listener, 1000);
$this->assertUpdateResults([], $expected_results, PreApplyEvent::class);
$this->assertUpdateResults(['my_module' => '9.8.1'], $expected_results, PreApplyEvent::class);
}
}
......@@ -11,13 +11,14 @@ use PhpTuf\ComposerStager\Domain\Value\PathList\PathListInterface;
/**
* Defines an update beginner which doesn't do anything.
*/
class Beginner extends InvocationRecorderBase implements BeginnerInterface {
class Beginner extends BypassedStagerServiceBase implements BeginnerInterface {
/**
* {@inheritdoc}
*/
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);
}
}
......@@ -2,6 +2,10 @@
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.
*
......@@ -9,7 +13,64 @@ namespace Drupal\package_manager_bypass;
* Stager services were called as expected. Kernel and unit tests should use
* regular mocks instead.
*/
abstract class InvocationRecorderBase {
abstract class BypassedStagerServiceBase {
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface
*/
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.
*
* @param \PhpTuf\ComposerStager\Domain\Value\Path\PathInterface $destination
* The path to which the fixture files should be mirrored.
*/
protected function copyFixtureFilesTo(PathInterface $destination): void {
$fixturePath = $this->state->get(static::class . ' fixture');
if ($fixturePath && is_dir($fixturePath)) {
$this->fileSystem->mirror($fixturePath, $destination->resolve(), NULL, [
'override' => TRUE,
'delete' => TRUE,
]);
}
}
/**
* Returns the arguments from every invocation of the main class method.
......@@ -18,7 +79,7 @@ abstract class InvocationRecorderBase {
* The arguments from every invocation of the main class method.
*/
public function getInvocationArguments(): array {
return \Drupal::state()->get(static::class, []);
return $this->state->get(static::class . ' arguments', []);
}
/**
......@@ -30,7 +91,7 @@ abstract class InvocationRecorderBase {
protected function saveInvocationArguments(...$arguments): void {
$invocations = $this->getInvocationArguments();
$invocations[] = $arguments;
\Drupal::state()->set(static::class, $invocations);
$this->state->set(static::class . ' arguments', $invocations);
}
}
......@@ -11,13 +11,24 @@ use PhpTuf\ComposerStager\Domain\Value\PathList\PathListInterface;
/**
* Defines an update committer which doesn't do any actual committing.
*/
class Committer extends InvocationRecorderBase implements CommitterInterface {
class Committer extends BypassedStagerServiceBase implements CommitterInterface {
/**
* {@inheritdoc}
*/
public function commit(PathInterface $stagingDir, PathInterface $activeDir, ?PathListInterface $exclusions = NULL, ?ProcessOutputCallbackInterface $callback = NULL, ?int $timeout = ProcessRunnerInterface::DEFAULT_TIMEOUT): void {
$this->saveInvocationArguments($stagingDir, $activeDir, $exclusions, $timeout);
$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.');
}
}
......@@ -5,6 +5,7 @@ namespace Drupal\package_manager_bypass;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Filesystem\Filesystem;
/**
* Defines services to bypass Package Manager's core functionality.
......@@ -17,21 +18,18 @@ class PackageManagerBypassServiceProvider extends ServiceProviderBase {
public function alter(ContainerBuilder $container) {
parent::alter($container);
$container->getDefinition('package_manager.beginner')
->setClass(Beginner::class)
->setArguments([]);
$container->getDefinition('package_manager.stager')
->setClass(Stager::class)
->setArguments([]);
$container->register('package_manager_bypass.committer')
->setClass(Committer::class)
->setPublic(FALSE)
->setDecoratedService('package_manager.committer')
->setArguments([
new Reference('package_manager_bypass.committer.inner'),
])
->setProperty('_serviceId', 'package_manager.committer');
$services = [
'package_manager.beginner' => Beginner::class,
'package_manager.stager' => Stager::class,
'package_manager.committer' => Committer::class,
];
$arguments = [
new Reference('state'),
new Reference(Filesystem::class),
];
foreach ($services as $id => $class) {
$container->getDefinition($id)->setClass($class)->setArguments($arguments);
}
}
}
......@@ -2,6 +2,7 @@
namespace Drupal\package_manager_bypass;
use Composer\Json\JsonFile;
use PhpTuf\ComposerStager\Domain\Core\Stager\StagerInterface;
use PhpTuf\ComposerStager\Domain\Service\ProcessOutputCallback\ProcessOutputCallbackInterface;
use PhpTuf\ComposerStager\Domain\Service\ProcessRunner\ProcessRunnerInterface;
......@@ -10,13 +11,36 @@ use PhpTuf\ComposerStager\Domain\Value\Path\PathInterface;
/**
* Defines an update stager which doesn't actually do anything.
*/
class Stager extends InvocationRecorderBase implements StagerInterface {
class Stager extends BypassedStagerServiceBase implements StagerInterface {
/**
* {@inheritdoc}
*/
public function stage(array $composerCommand, PathInterface $activeDir, PathInterface $stagingDir, ?ProcessOutputCallbackInterface $callback = NULL, ?int $timeout = ProcessRunnerInterface::DEFAULT_TIMEOUT): void {
$this->saveInvocationArguments($composerCommand, $stagingDir);
$this->copyFixtureFilesTo($stagingDir);
// If desired, simulate a change to the lock file (e.g., as a result of
// running `composer update`).
$lockFile = new JsonFile($stagingDir->resolve() . '/composer.lock');
$changeLockFile = $this->state->get(static::class . ' lock', TRUE);
if ($changeLockFile && $lockFile->exists()) {
$data = $lockFile->read();
$data['_time'] = microtime();
$lockFile->write($data);
}
}
/**
* Sets whether or not ::stage() should simulate a change in the lock file.
*
* @param bool $value
* (optional) Whether or not to simulate a change in the lock file when
* ::stage() is called. Defaults to TRUE.
*/
public static function setLockFileShouldChange(bool $value = TRUE): void {
\Drupal::state()->set(static::class . ' lock', $value);
}
}
name: 'Package Manager Test Fixture'
description: 'Provides a mechanism for functional tests to stage fixture files.'
type: module
package: Testing
dependencies:
- automatic_updates:package_manager
services:
package_manager_test_fixture.stager:
class: Drupal\package_manager_test_fixture\EventSubscriber\FixtureStager
arguments:
- '@state'
- '@Symfony\Component\Filesystem\Filesystem'
tags:
- { name: event_subscriber }
<?php
namespace Drupal\package_manager_test_fixture\EventSubscriber;
use Drupal\Core\State\StateInterface;
use Drupal\package_manager\Event\PostRequireEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Filesystem\Filesystem;
/**
* Defines an event subscriber which copies certain files into the staging area.
*
* This is most useful in conjunction with package_manager_bypass, which quietly
* turns all Composer Stager operations into no-ops. In such cases, no staging
* area will be physically created, but if a test needs to simulate certain
* conditions in a staging area without actually staging the active code base,
* this event subscriber is the way to do it.
*/
class FixtureStager implements EventSubscriberInterface {
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* The Symfony file system service.
*
* @var \Symfony\Component\Filesystem\Filesystem
*/
protected $fileSystem;
/**
* Constructs a FixtureStager.
*
* @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;
}
/**
* Copies files from a fixture into the staging area.
*
* Tests which use this functionality are responsible for cleaning up the
* staging area.
*
* @param \Drupal\package_manager\Event\PostRequireEvent $event
* The event object.
*
* @see \Drupal\Tests\automatic_updates\Functional\AutomaticUpdatesFunctionalTestBase::tearDown()
*/
public function copyFilesFromFixture(PostRequireEvent $event): void {
[$fixturePath, $changeLock] = $this->state->get(static::class);
if ($fixturePath && is_dir($fixturePath)) {
$destination = $event->getStage()->getStageDirectory();
$this->fileSystem->mirror($fixturePath, $destination, NULL, [
'override' => TRUE,
'delete' => TRUE,
]);
// Modify the lock file in the staging area, to simulate that a package
// was added, updated, or removed. Otherwise, tests must remember to
// disable the lock file validator.
// @see \Drupal\package_manager\Validator\LockFileValidator
$lock = $destination . '/composer.lock';
if ($changeLock && file_exists($lock)) {
$data = file_get_contents($lock);
$data = json_decode($data);
$data->_time = microtime();
file_put_contents($lock, json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
}
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
return [
PostRequireEvent::class => 'copyFilesFromFixture',
];
}
/**
* Sets the path of the fixture to copy into the staging area.
*
* @param string $path
* The path of the fixture to copy into the staging area.
* @param bool $change_lock
* (optional) Whether to change the lock file, in order to simulate the
* addition, updating, or removal of a package. Defaults to TRUE.
*/
public static function setFixturePath(string $path, bool $change_lock = TRUE): void {
\Drupal::state()->set(static::class, [$path, $change_lock]);
}
}
......@@ -7,7 +7,7 @@ use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\PreRequireEvent;
use Drupal\package_manager\Validator\LockFileValidator;
use Drupal\package_manager\ValidationResult;
use Drupal\package_manager_test_fixture\EventSubscriber\FixtureStager;
use Drupal\package_manager_bypass\Stager;
/**
* @coversDefaultClass \Drupal\package_manager\Validator\LockFileValidator
......@@ -123,10 +123,8 @@ class LockFileValidatorTest extends PackageManagerKernelTestBase {
* Tests validation when the staged and active lock files are identical.
*/
public function testApplyWithNoChange(): void {
// Ensure the lock file is not changed when the active directory is copied
// into the virtual staging area.
// @see \Drupal\package_manager_test_fixture\EventSubscriber\FixtureStager
FixtureStager::setFixturePath($this->activeDir, FALSE);
// Leave the staged lock file alone.
Stager::setLockFileShouldChange(FALSE);
$result = ValidationResult::createError([
'There are no pending Composer operations.',
......
......@@ -10,7 +10,7 @@ use Drupal\package_manager\Exception\StageException;
use Drupal\package_manager\Exception\StageValidationException;
use Drupal\package_manager\PathLocator;
use Drupal\package_manager\Stage;
use Drupal\package_manager_test_fixture\EventSubscriber\FixtureStager;
use Drupal\package_manager_bypass\Beginner;
use Drupal\Tests\package_manager\Traits\ValidationTestTrait;
use org\bovigo\vfs\vfsStream;
use org\bovigo\vfs\vfsStreamDirectory;
......@@ -34,7 +34,6 @@ abstract class PackageManagerKernelTestBase extends KernelTestBase {
protected static $modules = [
'package_manager',
'package_manager_bypass',
'package_manager_test_fixture',
];
/**
......@@ -213,9 +212,8 @@ abstract class PackageManagerKernelTestBase extends KernelTestBase {
$active_dir = $active_dir->url();
$path_locator = $this->mockPathLocator($active_dir);
// Ensure that the active directory is copied into the virtual staging area,
// even if Package Manager's operations are bypassed.
FixtureStager::setFixturePath($active_dir);
// Ensure the active directory will be copied into the virtual staging area.
Beginner::setFixturePath($active_dir);
// Since the path locator now points to a virtual file system, we need to
// replace the disk space validator with a test-only version that bypasses
......@@ -289,11 +287,23 @@ trait TestStageTrait {
*/
public function __construct(...$arguments) {
parent::__construct(...$arguments);
$mirror = new \ReflectionClass(Stage::class);
$this->tempStore->set($mirror->getConstant('TEMPSTORE_STAGING_ROOT_KEY'), PackageManagerKernelTestBase::$testStagingRoot);
$this->pathFactory = new TestPathFactory();
}
/**
* {@inheritdoc}
*/
public function create(?int $timeout = 300): string {
// Ensure that tests which need to successively create multiple stages are
// always using the same staging root, since the stored value may be deleted
// if the stage encounters an error during pre-create.
// @see \Drupal\package_manager\Stage::markAsAvailable()
$constant = new \ReflectionClassConstant(Stage::class, 'TEMPSTORE_STAGING_ROOT_KEY');
$this->tempStore->set($constant->getValue(), PackageManagerKernelTestBase::$testStagingRoot);
return parent::create($timeout);
}
/**
* {@inheritdoc}
*/
......
......@@ -2,6 +2,7 @@
namespace Drupal\Tests\package_manager\Kernel\PathExcluder;
use Drupal\package_manager_bypass\Beginner;
use Drupal\Tests\package_manager\Kernel\PackageManagerKernelTestBase;
/**
......@@ -37,6 +38,11 @@ class GitExcluderTest extends PackageManagerKernelTestBase {
mkdir($unreadable_dir, 0000);
$this->assertDirectoryIsNotReadable($unreadable_dir);
// Don't mirror the active directory into the virtual staging area, since
// the active directory contains an unreadable directory which will cause
// an exception.
Beginner::setFixturePath(NULL);
$this->createStage()->create();
}
......
......@@ -8,6 +8,7 @@ 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 Psr\Log\Test\TestLogger;
......@@ -180,6 +181,12 @@ 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 staging area 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);
......
......@@ -11,6 +11,7 @@ use Drupal\package_manager\Event\PostApplyEvent;
use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\package_manager\Event\StageEvent;
use Drupal\package_manager\Exception\StageException;
use Drupal\package_manager_bypass\Beginner;
/**
* @coversDefaultClass \Drupal\package_manager\Stage
......@@ -30,10 +31,6 @@ class StageTest extends PackageManagerKernelTestBase {
* {@inheritdoc}
*/
protected function setUp(): void {
// Disable the symlink validator, since this test doesn't use a virtual
// project, but the running code base may have symlinks that don't affect
// the test.
$this->disableValidators[] = 'package_manager.validator.symlink';
parent::setUp();
$this->installConfig('system');
......@@ -70,6 +67,9 @@ class StageTest extends PackageManagerKernelTestBase {
// Even though we're using a virtual project, we want to test what happens
// when we aren't.
static::$testStagingRoot = NULL;
// Don't mirror the active directory from the virtual project into the
// real file system.
Beginner::setFixturePath(NULL);
$stage = $this->createStage();
$id = $stage->create();
......@@ -191,6 +191,7 @@ class StageTest extends PackageManagerKernelTestBase {
$stage = $this->createStage();
$stage->create();
$stage->require(['ext-json:*']);
if ($expect_exception) {
$this->expectException(StageException::class);
$this->expectExceptionMessage('Cannot destroy the staging area while it is being applied to the active directory.');
......@@ -230,6 +231,7 @@ class StageTest extends PackageManagerKernelTestBase {
$stage = $this->createStage();
$stage->create();
$stage->require(['ext-json:*']);
$stage->apply();
}
......@@ -239,6 +241,7 @@ class StageTest extends PackageManagerKernelTestBase {
public function testTimeouts(): void {
$stage = $this->createStage();
$stage->create(420);
$stage->require(['ext-json:*']);
$stage->apply();
$timeouts = [
......
......@@ -56,10 +56,6 @@ class SymlinkValidatorTest extends PackageManagerKernelTestBase {
$stage = $this->createStage();
$stage->create();
// Simulate updating a package. This will copy the active directory into
// the (virtual) staging area.
// @see ::createVirtualProject()
// @see \Drupal\package_manager_test_fixture\EventSubscriber\FixtureStager::copyFilesFromFixture()
$stage->require(['composer/semver:^3']);
// @see \Drupal\Tests\package_manager\Kernel\TestSymlinkValidator::isLink()
......@@ -89,10 +85,6 @@ class SymlinkValidatorTest extends PackageManagerKernelTestBase {
$stage = $this->createStage();
$stage->create();
// Simulate updating a package. This will copy the active directory into
// the (virtual) staging area.
// @see ::createVirtualProject()
// @see \Drupal\package_manager_test_fixture\EventSubscriber\FixtureStager::copyFilesFromFixture()
$stage->require(['composer/semver:^3']);
$active_dir = $this->container->get('package_manager.path_locator')
......
......@@ -14,18 +14,18 @@ trait PackageManagerBypassTestTrait {
* The expected number of times an update was staged.
*/
private function assertUpdateStagedTimes(int $attempted_times): void {
/** @var \Drupal\package_manager_bypass\InvocationRecorderBase $beginner */
/** @var \Drupal\package_manager_bypass\BypassedStagerServiceBase $beginner */
$beginner = $this->container->get('package_manager.beginner');
$this->assertCount($attempted_times, $beginner->getInvocationArguments());
/** @var \Drupal\package_manager_bypass\InvocationRecorderBase $stager */
/** @var \Drupal\package_manager_bypass\BypassedStagerServiceBase $stager */
$stager = $this->container->get('package_manager.stager');
// If an update was attempted, then there will be two calls to the stager:
// one to change the constraints in composer.json, and another to actually
// update the installed dependencies.
$this->assertCount($attempted_times * 2, $stager->getInvocationArguments());
/** @var \Drupal\package_manager_bypass\InvocationRecorderBase $committer */
/** @var \Drupal\package_manager_bypass\BypassedStagerServiceBase $committer */
$committer = $this->container->get('package_manager.committer');
$this->assertEmpty($committer->getInvocationArguments());
}
......
......@@ -23,7 +23,6 @@ class AvailableUpdatesReportTest extends AutomaticUpdatesFunctionalTestBase {
'block',
'automatic_updates',
'automatic_updates_test',
'package_manager_test_fixture',
];
/**
......
......@@ -8,7 +8,7 @@ use Drupal\automatic_updates_test\Datetime\TestTime;
use Drupal\automatic_updates_test\EventSubscriber\TestSubscriber1;
use Drupal\automatic_updates_test2\EventSubscriber\TestSubscriber2;
use Drupal\Core\Url;
use Drupal\package_manager_test_fixture\EventSubscriber\FixtureStager;
use Drupal\package_manager_bypass\Stager;
use Drupal\system\SystemManager;
use Drupal\Tests\automatic_updates\Traits\ValidationTestTrait;
use Drupal\Tests\Traits\Core\CronRunTrait;
......@@ -399,7 +399,6 @@ class ReadinessValidationTest extends AutomaticUpdatesFunctionalTestBase {
$this->container->get('module_installer')->install([
'automatic_updates',
'automatic_updates_test',
'package_manager_test_fixture',
]);
// Because all actual staging operations are bypassed by
// package_manager_bypass (enabled by the parent class), disable these
......@@ -423,7 +422,7 @@ class ReadinessValidationTest extends AutomaticUpdatesFunctionalTestBase {
// readiness check (without storing the results), and the checker is no
// longer raising an error.
$this->drupalGet('/admin/modules/automatic-update');
FixtureStager::setFixturePath(__DIR__ . '/../../fixtures/staged/9.8.1');
Stager::setFixturePath(__DIR__ . '/../../fixtures/staged/9.8.1');
$assert_session->buttonExists('Update');
// Ensure that the previous results are still displayed on another admin
// page, to confirm that the updater form is not discarding the previous
......
......@@ -2,7 +2,7 @@
namespace Drupal\Tests\automatic_updates\Functional;
use Drupal\package_manager_test_fixture\EventSubscriber\FixtureStager;
use Drupal\package_manager_bypass\Stager;
/**
* Tests that only one Automatic Update operation can be performed at a time.
......@@ -22,7 +22,6 @@ class UpdateLockTest extends AutomaticUpdatesFunctionalTestBase {
protected static $modules = [
'automatic_updates',
'automatic_updates_test',
'package_manager_test_fixture',
];
/**
......@@ -53,7 +52,7 @@ class UpdateLockTest extends AutomaticUpdatesFunctionalTestBase {
// We should be able to get partway through an update without issue.
$this->drupalLogin($user_1);
$this->drupalGet('/admin/modules/automatic-update');
FixtureStager::setFixturePath(__DIR__ . '/../../fixtures/staged/9.8.1');
Stager::setFixturePath(__DIR__ . '/../../fixtures/staged/9.8.1');
$page->pressButton('Update');
$this->checkForMetaRefresh();
$this->assertUpdateReady('9.8.1');
......
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