Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
PackageUpdateTest.php 6.32 KiB
<?php

namespace Drupal\Tests\package_manager\Build;

/**
 * Tests updating packages in a staging area.
 *
 * @group package_manager
 */
class PackageUpdateTest extends TemplateProjectTestBase {

  /**
   * Tests updating packages in a staging area.
   */
  public function testPackageUpdate(): void {
    $this->createTestProject('RecommendedProject');

    $this->addRepository('alpha', __DIR__ . '/../../fixtures/alpha/1.0.0');
    $this->addRepository('updated_module', __DIR__ . '/../../fixtures/updated_module/1.0.0');
    $this->runComposer('COMPOSER_MIRROR_PATH_REPOS=1 composer require drupal/alpha drupal/updated_module --update-with-all-dependencies', 'project');

    $this->installQuickStart('minimal');
    $this->formLogin($this->adminUsername, $this->adminPassword);
    // The updated_module provides actual Drupal-facing functionality that we're
    // testing as well, so we need to install it.
    $this->installModules(['package_manager_test_api', 'updated_module']);

    // Change both modules' upstream version.
    $this->addRepository('alpha', __DIR__ . '/../../fixtures/alpha/1.1.0');
    $this->addRepository('updated_module', __DIR__ . '/../../fixtures/updated_module/1.1.0');

    // Use the API endpoint to create a stage and update updated_module to
    // 1.1.0. Even though both modules have version 1.1.0 available, only
    // updated_module should be updated. We ask the API to return the contents
    // of both modules' composer.json files, so we can assert that they were
    // updated to the versions we expect.
    // @see \Drupal\package_manager_test_api\ApiController::run()
    $query = http_build_query([
      'runtime' => [
        'drupal/updated_module:1.1.0',
      ],
      'files_to_return' => [
        'web/modules/contrib/alpha/composer.json',
        'web/modules/contrib/updated_module/composer.json',
        'bravo.txt',
        "system_changes.json",
      ],
    ]);
    $this->visit("/package-manager-test-api?$query");
    $mink = $this->getMink();
    $mink->assertSession()->statusCodeEquals(200);

    $file_contents = $mink->getSession()->getPage()->getContent();
    $file_contents = json_decode($file_contents, TRUE);

    $expected_versions = [
      'alpha' => '1.0.0',
      'updated_module' => '1.1.0',
    ];
    foreach ($expected_versions as $module_name => $expected_version) {
      $path = "web/modules/contrib/$module_name/composer.json";
      $module_composer_json = json_decode($file_contents[$path]);
      $this->assertSame($expected_version, $module_composer_json->version);
    }
    // The post-apply event subscriber in updated_module 1.1.0 should have
    // 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',
      '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 = [
      // Existing functions will still use the pre-update version.
      'return value of existing global function' => 'pre-update-value',
      // New functions that were added in .module files will not be available.
      'new global function exists' => 'not 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',
      // Existing class should be available.
      'ChangedClass exists' => 'exists',
      // Existing class will still use the pre-update version.
      'value of ChangedClass' => 'Before Update',
      // Classes loaded in pre-apply or before and deleted from the updated module should
      // be available.
      'LoadedAndDeletedClass exists' => 'exists',
      'value of LoadedAndDeletedClass' => 'This class will be loaded and then deleted',
      // 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']);
  }

}