Forked from
project / automatic_updates
407 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ExtensionUpdaterTest.php 6.67 KiB
<?php
namespace Drupal\Tests\automatic_updates_extensions\Kernel;
use Drupal\automatic_updates\Exception\UpdateException;
use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\PreRequireEvent;
use Drupal\package_manager\ValidationResult;
use Drupal\package_manager_test_validation\EventSubscriber\TestSubscriber;
use Drupal\Tests\user\Traits\UserCreationTrait;
/**
* @coversDefaultClass \Drupal\automatic_updates_extensions\ExtensionUpdater
*
* @group automatic_updates_extensions
*/
class ExtensionUpdaterTest extends AutomaticUpdatesExtensionsKernelTestBase {
use UserCreationTrait;
/**
* {@inheritdoc}
*/
protected static $modules = [
'automatic_updates',
'automatic_updates_test',
'automatic_updates_extensions',
'user',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
// This test doesn't need to validate that the test projects used are in the
// codebase. Therefore, we need to disable the following validators that
// require real Drupal projects.
$this->disableValidators[] = 'automatic_updates_extensions.validator.target_release';
parent::setUp();
$this->installEntitySchema('user');
// Create a user who will own the stage even after the container is rebuilt.
$user = $this->createUser([], NULL, TRUE, ['uid' => 2]);
$this->setCurrentUser($user);
$this->createVirtualProject(__DIR__ . '/../../fixtures/fake-site');
}
/**
* Tests that correct versions are staged after calling ::begin().
*/
public function testCorrectVersionsStaged(): void {
$id = $this->container->get('automatic_updates_extensions.updater')->begin([
'my_module' => '9.8.1',
// Use a legacy version number to ensure they are converted to semantic
// version numbers which will work with the drupal.org Composer facade.
'my_dev_module' => '8.x-1.2-alpha1',
]);
$user = $this->container->get('current_user')->getAccount();
// Rebuild the container to ensure the package versions are persisted.
/** @var \Drupal\Core\DrupalKernel $kernel */
$kernel = $this->container->get('kernel');
$kernel->rebuildContainer();
$this->container = $kernel->getContainer();
// Keep using the user account we created.
$this->setCurrentUser($user);
$extension_updater = $this->container->get('automatic_updates_extensions.updater');
// Ensure that the target package versions are what we expect.
$expected_versions = [
'production' => [
'drupal/my_module' => '9.8.1',
],
'dev' => [
'drupal/my_dev_module' => '1.2.0-alpha1',
],
];
$this->assertSame($expected_versions, $extension_updater->claim($id)->getPackageVersions());
// When we call ExtensionUpdater::stage(), the stored project versions
// should be read from state and passed to Composer Stager's Stager service,
// in the form of a Composer command. This is done using
// package_manager_bypass's invocation recorder, rather than a regular mock,
// in order to test that the invocation recorder itself works. The
// production requirements are changed first, followed by the dev
// requirements. Then the installed packages are updated. This is tested
// functionally in Package Manager.
// @see \Drupal\Tests\package_manager\Build\StagedUpdateTest
$expected_arguments = [
[
'require',
'--no-update',
'drupal/my_module:9.8.1',
],
[
'require',
'--dev',
'--no-update',
'drupal/my_dev_module:1.2.0-alpha1',
],
[
'update',
'--with-all-dependencies',
'drupal/my_module:9.8.1',
'drupal/my_dev_module:1.2.0-alpha1',
],
];
$extension_updater->stage();
$actual_arguments = $this->container->get('package_manager.stager')
->getInvocationArguments();
$this->assertSame(count($expected_arguments), count($actual_arguments));
foreach ($actual_arguments as $i => [$arguments]) {
$this->assertSame($expected_arguments[$i], $arguments);
}
}
/**
* Tests that attempting to update an install profile throws an exception.
*/
public function testUpdatingInstallProfile(): void {
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage("The project contrib_profile1 cannot be updated because updating install profiles is not supported.");
$this->container->get('automatic_updates_extensions.updater')
->begin([
'contrib_profile1' => '1.1.0',
]);
}
/**
* Tests that an exception is thrown when calling begin() with no projects.
*/
public function testNoProjectsInBegin(): void {
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('No projects to begin the update');
$this->container->get('automatic_updates_extensions.updater')->begin([]);
}
/**
* Tests exception if a Drupal project unknown to composer sent to ::begin().
*/
public function testUnknownDrupalProject(): void {
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage("The project my_module_unknown is not a Drupal project known to Composer and cannot be updated.");
$this->container->get('automatic_updates_extensions.updater')->begin([
'my_module_unknown' => '9.8.1',
]);
}
/**
* Tests UpdateException handling.
*
* @param string $event_class
* The stage life cycle event which should raise an error.
*
* @dataProvider providerUpdateException
*/
public function testUpdateException(string $event_class): void {
$this->createVirtualProject(__DIR__ . '/../../fixtures/fake-site');
$extension_updater = $this->container->get('automatic_updates_extensions.updater');
$results = [
ValidationResult::createError(['An error of some sorts.']),
];
TestSubscriber::setTestResult($results, $event_class);
try {
$extension_updater->begin(['my_module' => '9.8.1']);
$extension_updater->stage();
$extension_updater->apply();
$this->fail('Expected an exception, but none was raised.');
}
catch (UpdateException $e) {
$this->assertStringStartsWith('An error of some sorts.', $e->getMessage());
$this->assertInstanceOf($event_class, $e->event);
}
}
/**
* Data provider for testUpdateException().
*
* @return string[][]
* The test cases.
*/
public function providerUpdateException(): array {
return [
'pre-create exception' => [
PreCreateEvent::class,
],
'pre-require exception' => [
PreRequireEvent::class,
],
'pre-apply exception' => [
PreApplyEvent::class,
],
];
}
}