Skip to content
Snippets Groups Projects
Forked from project / automatic_updates
913 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ModifiedFilesTest.php 6.42 KiB
<?php

namespace Drupal\Tests\automatic_updates\Build;

use Drupal\Component\Utility\Html;
use Drupal\Tests\automatic_updates\Build\QuickStart\QuickStartTestBase;
use Symfony\Component\Filesystem\Filesystem as SymfonyFilesystem;

/**
 * @coversDefaultClass \Drupal\automatic_updates\Services\ModifiedFiles
 *
 * @group Update
 *
 * @requires externalCommand composer
 * @requires externalCommand curl
 * @requires externalCommand git
 * @requires externalCommand tar
 */
class ModifiedFilesTest extends QuickStartTestBase {

  /**
   * Symfony file system.
   *
   * @var \Symfony\Component\Filesystem\Filesystem
   */
  protected $symfonyFileSystem;

  /**
   * {@inheritdoc}
   */
  protected function setUp() {
    parent::setUp();
    $this->symfonyFileSystem = new SymfonyFilesystem();
  }

  /**
   * @covers ::getModifiedFiles
   * @dataProvider coreProjectProvider
   */
  public function testCoreModified($version, array $modifications = []) {
    $this->copyCodebase();

    // We have to fetch the tags for this shallow repo. It might not be a
    // shallow clone, therefore we use executeCommand instead of assertCommand.
    $this->executeCommand('git fetch --unshallow  --tags');
    $this->symfonyFileSystem->chmod($this->getWorkspaceDirectory() . '/sites/default', 0700, 0000);
    $this->executeCommand("git checkout $version -f");
    $this->assertCommandSuccessful();

    // Assert modifications.
    $this->assertModifications('core', 'drupal', $modifications);
  }

  /**
   * @covers ::getModifiedFiles
   * @dataProvider contribProjectsProvider
   */
  public function testContribModified($project, $project_type, $version, array $modifications = []) {
    $this->copyCodebase();

    // Download the project.
    $this->symfonyFileSystem->mkdir($this->getWorkspaceDirectory() . "/{$project_type}s/contrib/$project");
    $this->executeCommand("curl -fsSL https://ftp.drupal.org/files/projects/$project-$version.tar.gz | tar xvz -C {$project_type}s/contrib/$project --strip 1");
    $this->assertCommandSuccessful();

    // Assert modifications.
    $this->assertModifications($project_type, $project, $modifications);
  }

  /**
   * Core project data provider.
   */
  public function coreProjectProvider() {
    $datum[] = [
      'version' => '8.7.3',
      'modifications' => [
        'core/LICENSE.txt',
      ],
    ];
    return $datum;
  }

  /**
   * Contrib project data provider.
   */
  public function contribProjectsProvider() {
    $datum[] = [
      'project' => 'bootstrap',
      'project_type' => 'theme',
      'version' => '8.x-3.20',
      'modifications' => [
        'themes/contrib/bootstrap/LICENSE.txt',
      ],
    ];
    $datum[] = [
      'project' => 'token',
      'project_type' => 'module',
      'version' => '8.x-1.5',
      'modifications' => [
        'modules/contrib/token/LICENSE.txt',
      ],
    ];
    return $datum;
  }

  /**
   * Assert modified files.
   *
   * @param string $project_type
   *   The project type.
   * @param string $project
   *   The project to assert.
   * @param array $modifications
   *   The modified files to assert.
   */
  protected function assertModifications($project_type, $project, array $modifications) {
    $this->symfonyFileSystem->chmod($this->getWorkspaceDirectory() . '/sites/default', 0700, 0000);
    $this->executeCommand('COMPOSER_DISCARD_CHANGES=true composer install --no-dev --no-interaction');
    $this->assertErrorOutputContains('Generating autoload files');
    $this->executeCommand('COMPOSER_DISCARD_CHANGES=true composer require ocramius/package-versions:^1.4 webflo/drupal-finder:^1.1 composer/semver:^1.0 drupal/php-signify:^1.0@dev --no-interaction');
    $this->assertErrorOutputContains('Generating autoload files');
    $this->installQuickStart('minimal');

    // Currently, this test has to use extension_discovery_scan_tests so we can
    // enable test modules.
    $this->symfonyFileSystem->chmod($this->getWorkspaceDirectory() . '/sites/default', 0750, 0000);
    $this->symfonyFileSystem->chmod($this->getWorkspaceDirectory() . '/sites/default/settings.php', 0640, 0000);
    $settings_php = $this->getWorkspaceDirectory() . '/sites/default/settings.php';
    $this->symfonyFileSystem->appendToFile($settings_php, PHP_EOL . '$settings[\'extension_discovery_scan_tests\'] = TRUE;' . PHP_EOL);
    // Intentionally mark composer.json and composer.lock as ignored.
    $this->symfonyFileSystem->appendToFile($settings_php, PHP_EOL . '$config[\'automatic_updates.settings\'][\'ignored_paths\'] = "composer.json\ncomposer.lock\nmodules/custom/*\nthemes/custom/*\nprofiles/custom/*";' . PHP_EOL);

    // Restart server for config override to apply.
    $this->stopServer();
    $this->standUpServer();

    // Log in so that we can install modules.
    $this->formLogin($this->adminUsername, $this->adminPassword);
    $this->moduleEnable('update');
    $this->moduleEnable('automatic_updates');
    $this->moduleEnable('test_automatic_updates');

    // Assert that the site is functional.
    $this->visit();
    $this->assertDrupalVisit();

    // Validate project is not modified.
    $this->visit("/automatic_updates/modified-files/$project_type/$project");
    $assert = $this->getMink()->assertSession();
    $assert->statusCodeEquals(200);
    $assert->pageTextContains('No modified files!');

    // Assert modifications.
    $this->assertNotEmpty($modifications);
    foreach ($modifications as $modification) {
      $file = $this->getWorkspaceDirectory() . DIRECTORY_SEPARATOR . $modification;
      $this->fileExists($file);
      $this->symfonyFileSystem->appendToFile($file, PHP_EOL . '// file is modified' . PHP_EOL);
    }
    $this->visit("/automatic_updates/modified-files/$project_type/$project");
    $assert->pageTextContains('Modified files include:');
    foreach ($modifications as $modification) {
      $assert->pageTextContains($modification);
    }
  }

  /**
   * Helper method that uses Drupal's module page to enable a module.
   */
  protected function moduleEnable($module_name) {
    $this->visit('/admin/modules');
    $field = Html::getClass("edit-modules $module_name enable");
    // No need to enable a module if it is already enabled.
    if ($this->getMink()->getSession()->getPage()->findField($field)->isChecked()) {
      return;
    }
    $assert = $this->getMink()->assertSession();
    $assert->fieldExists($field)->check();
    $session = $this->getMink()->getSession();
    $session->getPage()->findButton('Install')->submit();
    $assert->fieldExists($field)->isChecked();
  }

}