automatic_updates-8.x-2.x-dev/tests/src/Kernel/UpdateSandboxManagerTest.php

tests/src/Kernel/UpdateSandboxManagerTest.php
<?php

declare(strict_types=1);

namespace Drupal\Tests\automatic_updates\Kernel;

use Drupal\automatic_updates\UpdateSandboxManager;
use Drupal\package_manager\Exception\ApplyFailedException;
use Drupal\package_manager\Exception\SandboxException;
use Drupal\package_manager_bypass\LoggingCommitter;
use Drupal\Tests\user\Traits\UserCreationTrait;
use PhpTuf\ComposerStager\API\Core\StagerInterface;
use PhpTuf\ComposerStager\API\Exception\ExceptionInterface;
use PhpTuf\ComposerStager\API\Exception\InvalidArgumentException;

/**
 * @coversDefaultClass \Drupal\automatic_updates\UpdateSandboxManager
 * @group automatic_updates
 * @internal
 */
class UpdateSandboxManagerTest extends AutomaticUpdatesKernelTestBase {

  use UserCreationTrait;

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'automatic_updates',
    'automatic_updates_test',
    'user',
  ];

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();
    $this->installEntitySchema('user');
  }

  /**
   * Tests that correct versions are staged after calling ::begin().
   */
  public function testCorrectVersionsStaged(): void {
    // Simulate that we're running Drupal 9.8.0 and a security update to 9.8.1
    // is available.
    $this->setCoreVersion('9.8.0');
    $this->setReleaseMetadata([
      'drupal' => static::getDrupalRoot() . '/core/modules/package_manager/tests/fixtures/release-history/drupal.9.8.1-security.xml',
    ]);

    // Create a user who will own the stage even after the container is rebuilt.
    $user = $this->createUser([], NULL, TRUE, ['uid' => 2]);
    $this->setCurrentUser($user);

    $id = $this->container->get(UpdateSandboxManager::class)->begin([
      'drupal' => '9.8.1',
    ]);
    // 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);

    $sandbox_manager = $this->container->get(UpdateSandboxManager::class);

    // Ensure that the target package versions are what we expect.
    $expected_versions = [
      'production' => [
        'drupal/core-recommended' => '9.8.1',
      ],
      'dev' => [
        'drupal/core-dev' => '9.8.1',
      ],
    ];
    $this->assertSame($expected_versions, $sandbox_manager->claim($id)->getPackageVersions());

    // When we call UpdateStage::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/core-recommended:9.8.1',
      ],
      [
        'require',
        '--dev',
        '--no-update',
        'drupal/core-dev:9.8.1',
      ],
      [
        'update',
        '--with-all-dependencies',
        '--optimize-autoloader',
        '--minimal-changes',
        'drupal/core-recommended:9.8.1',
        'drupal/core-dev:9.8.1',
      ],
    ];
    $sandbox_manager->stage();

    $actual_arguments = $this->container->get(StagerInterface::class)
      ->getInvocationArguments();

    $this->assertCount(count($expected_arguments), $actual_arguments);
    foreach ($actual_arguments as $i => [$arguments]) {
      $this->assertSame($expected_arguments[$i], $arguments);
    }
  }

  /**
   * @covers ::begin
   *
   * @dataProvider providerInvalidProjectVersions
   */
  public function testInvalidProjectVersions(array $project_versions): void {
    $this->expectException(\InvalidArgumentException::class);
    $this->expectExceptionMessage('Currently only updates to Drupal core are supported.');
    $this->container->get(UpdateSandboxManager::class)->begin($project_versions);
  }

  /**
   * Data provider for testInvalidProjectVersions().
   *
   * @return mixed[][]
   *   The test cases.
   */
  public static function providerInvalidProjectVersions(): array {
    return [
      'only not drupal' => [['not_drupal' => '1.1.3']],
      'not drupal and drupal' => [['drupal' => '9.8.0', 'not_drupal' => '1.2.3']],
      'empty' => [[]],
    ];
  }

  /**
   * Data provider for testCommitException().
   *
   * @return string[][]
   *   The test cases.
   */
  public static function providerCommitException(): array {
    return [
      'RuntimeException' => [
        \RuntimeException::class,
        ApplyFailedException::class,
      ],
      'InvalidArgumentException' => [
        InvalidArgumentException::class,
        SandboxException::class,
      ],
      'Exception' => [
        'Exception',
        ApplyFailedException::class,
      ],
    ];
  }

  /**
   * Tests exception handling during calls to Composer Stager commit.
   *
   * @param string $thrown_class
   *   The throwable class that should be thrown by Composer Stager.
   * @param string|null $expected_class
   *   The expected exception class.
   *
   * @dataProvider providerCommitException
   */
  public function testCommitException(string $thrown_class, ?string $expected_class = NULL): void {
    $this->getStageFixtureManipulator()->setCorePackageVersion('9.8.1');

    $sandbox_manager = $this->container->get(UpdateSandboxManager::class);
    $sandbox_manager->begin([
      'drupal' => '9.8.1',
    ]);
    $sandbox_manager->stage();
    $thrown_message = 'A very bad thing happened';
    // Composer Stager's exception messages are usually translatable, so they
    // need to be wrapped by a TranslatableMessage object.
    if (is_subclass_of($thrown_class, ExceptionInterface::class)) {
      $thrown_message = $this->createComposeStagerMessage($thrown_message);
    }
    LoggingCommitter::setException($thrown_class, $thrown_message, 123);
    $this->expectException($expected_class);
    $expected_message = $expected_class === ApplyFailedException::class ?
      "Automatic updates failed to apply, and the site is in an indeterminate state. Consider restoring the code and database from a backup."
      : $thrown_message;
    $this->expectExceptionMessage((string) $expected_message);
    $this->expectExceptionCode(123);
    $sandbox_manager->apply();
  }

  /**
   * Tests that setLogger is called on the update stage service.
   */
  public function testLoggerIsSetByContainer(): void {
    $stage_method_calls = $this->container->getDefinition(UpdateSandboxManager::class)->getMethodCalls();
    $this->assertSame('setLogger', $stage_method_calls[0][0]);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc