api-8.x-1.x-dev/tests/src/Functional/CruftTest.php

tests/src/Functional/CruftTest.php
<?php

namespace Drupal\Tests\api\Functional;

use Drupal\api\Entity\Branch;
use Drupal\api\Entity\DocBlock;
use Drupal\api\Entity\ExternalBranch;
use Drupal\api\Entity\PhpBranch;
use Drupal\api\Parser;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
use Symfony\Component\Finder\SplFileInfo;

/**
 * Tests that "cruft" in the API module is removed appropriately.
 *
 * @group api
 */
class CruftTest extends WebPagesBase {

  /**
   * The directory where the source files to parse are located.
   *
   * @var string
   */
  protected $sourceFileDirectory;

  /**
   * {@inheritdoc}
   */
  protected function setUp() : void {
    $this->baseSetUp();

    // Set up a temporary copy of the files to parse.
    $source = $this->apiModulePath . '/tests/files/sample';
    $this->sourceFileDirectory = realpath($this->publicFilesDirectory) . '/sample_files';
    self::recursiveCopyFiles($source, $this->sourceFileDirectory);
    $this->assertDirectoryExists($this->sourceFileDirectory);

    // Set up a new super-user.
    $this->drupalAdminLogin();

    // Set up comment settings.
    $this->drupalGet('admin/config/development/api/comments');
    $this->submitForm(['status' => (string) CommentItemInterface::OPEN], 'Save configuration');

    // We don't need the PHP branch for this test, so for speed, remove it.
    $this->removePhpBranch();
  }

  /**
   * Tests that cruft is removed appropriately.
   */
  public function testCruftRemoval() {
    $counts = [
      'api_project' => 0,
      'api_branch' => 0,
      'api_php_branch' => 0,
      'api_external_branch' => 0,
      'api_branch_docblock' => 0,
      'api_php_branch_documentation' => 0,
      'api_external_branch_documentation' => 0,
      'api_branch_docblock_function' => 0,
      'api_branch_docblock_class_member' => 0,
      'api_branch_docblock_override' => 0,
      'api_branch_docblock_file' => 0,
      'api_branch_docblock_namespace' => 0,
    ];
    $this->verifyCounts($counts, 0, 'No branches');

    // Add a branch without the usual exclude directory excluded.
    $this->setUpBranchUi(NULL, TRUE, [
      'directory' => $this->sourceFileDirectory,
      'excluded' => '',
    ]);
    $counts['api_project'] = 1;
    $counts['api_branch'] = 1;
    $this->clearCache();
    $this->verifyCounts($counts, 0, 'Branch added');

    // Run the branch update function and verify counts. There should be
    // records for each file.
    $this->cronRun();
    $this->processApiParseQueue();
    $counts['api_branch_docblock'] = 80;
    $counts['api_branch_docblock_file'] = 12;
    $counts['api_branch_docblock_function'] = 34;
    $counts['api_branch_docblock_class_member'] = 26;
    $counts['api_branch_docblock_override'] = 23;
    $this->verifyCounts($counts, 0, 'Add and update branch with no exclusion');

    // Update the branch to exclude the exclude directory.
    $default_branch = $this->getBranch();
    $this->drupalGet('admin/config/development/api/branch/' . $default_branch->id() . '/edit');
    $this->submitForm([
      'excluded_directories' => $this->sourceFileDirectory . '/to_exclude',
    ], 'Save');
    $this->drupalGet('admin/config/development/api/branch/' . $default_branch->id() . '/edit');
    $this->clearCache();
    $default_branch = Branch::load($default_branch->id());

    // Orphan files (after excluded) are only deleted after a number of days.
    // Set that in the configuration and also fake the date of the files, to
    // see how they go away.
    $this->drupalGet('admin/config/development/api');
    $this->submitForm([
      'default_branch_project' => $default_branch->getSlug() . '|' . $default_branch->id(),
      'remove_orphan_files' => 5,
    ], 'Save configuration');
    $this->clearCache();
    $docBlock = DocBlock::findFileByFileName('to_exclude/excluded.php', $default_branch);
    $this->assertNotEmpty($docBlock);
    $docBlock = DocBlock::load($docBlock);
    $docBlock->getDocFile()->setCreatedTime(strtotime('-10 days'))->save();
    // This should get rid of the file and related entities.
    $this->cronRun();
    $this->checkAndClearLog(['DocBlock excluded.php deleted.']);
    $this->clearCache();
    $docBlock = DocBlock::findFileByFileName('to_exclude/excluded.php', $default_branch);
    $this->assertEmpty($docBlock);

    // Parse everything and re-verify counts.
    $default_branch->reParse();
    $this->cronRun();
    $this->processApiParseQueue();
    $this->clearCache();
    // Make sure the file was not recreated.
    $docBlock = DocBlock::findFileByFileName('to_exclude/excluded.php', $default_branch);
    $this->assertEmpty($docBlock);
    // excluded.php has 8 docblocks but samp_GRP-6.x has a definition in
    // sample.php after exclusion so the difference is 7.
    $counts['api_branch_docblock'] -= 7;
    $counts['api_branch_docblock_file'] -= 1;
    // excluded_function(), non_duplicate_name(), some_name()
    $counts['api_branch_docblock_function'] -= 3;
    // Sample and SampleInterface were empty in excluded.php but now their
    // correct version is used from classes.php and so Sample::CONSTANT,
    // Sample::$property, Sample::foo(), Sample::baz() are now a member of
    // SubSample and SampleInterface::foo is a member of Sample2.
    $counts['api_branch_docblock_class_member'] += 5;
    $this->verifyCounts($counts, 0, 'Parse the branch');

    // Mark branch for update and reparsing.
    $this->drupalGet('admin/config/development/api/branch/' . $default_branch->id() . '/parse');
    // Check counts and log; counts should stay the same.
    $this->clearCache();
    $this->cronRun();
    $this->processApiParseQueue();
    $this->verifyCounts($counts, 0, 'Reparse the branch');

    // Add one comment in the main directory and one in the subdirectory, and
    // verify counts.
    $this->drupalGet('api/' . $default_branch->getProject()->getSlug() . '/classes.php/class/Sample');
    $this->submitForm([
      'subject' => 'Subject 1',
      'field_api_comment_body' => 'Comment 1 body',
    ], 'Save');
    $this->assertSession()->responseContains('Your comment has been posted');

    $this->drupalGet('api/' . $default_branch->getProject()->getSlug() . '/subdirectory!classes-subdir.php/class/SampleInSubDir');
    $this->submitForm([
      'subject' => 'Subject 2',
      'field_api_comment_body' => 'Comment 2 body',
    ], 'Save');
    $this->assertSession()->responseContains('Your comment has been posted');

    $counts['comment'] = 2;
    $this->verifyCounts($counts, 0, 'Add two comments');

    $this->clearCache();
    $this->drupalGet('api/' . $default_branch->getProject()->getSlug() . '/classes.php/class/Sample');
    $this->assertSession()->linkExists('Subject 1', 0, 'Comment subject appears');
    $this->assertSession()->responseContains('Comment 1 body');

    // Delete the branch, and verify counts.
    $this->drupalGet('admin/config/development/api/branch/' . $default_branch->id() . '/delete');
    $this->submitForm([], 'Delete');
    $this->cronRun();
    $this->processApiDeleteQueue();
    $this->clearCache();
    $counts['api_branch'] = 0;
    $counts['comment'] = 0;
    $counts['api_branch_docblock_file'] = 0;
    $counts['api_branch_docblock'] = 0;
    $counts['api_branch_docblock_function'] = 0;
    $counts['api_branch_docblock_class_member'] = 0;
    $counts['api_branch_docblock_override'] = 0;
    // At this point, make sure the reference storage table is cleared out
    // too. We haven't been tracking it.
    $counts['api_branch_docblock_reference'] = 0;
    $counts['api_branch_docblock_reference_count'] = 0;
    $this->verifyCounts($counts, 0, 'Branch deleted');
    // Go back to not tracking reference storage.
    unset($counts['api_branch_docblock_reference']);
    unset($counts['api_branch_docblock_reference_count']);

    // Add a job using the deleted branch to the queue, and attempt to parse it.
    // Verify that the log message is generated.
    $this->clearCache();
    $parser = \Drupal::service('api.parser');
    $queue = \Drupal::service('queue')->get(Parser::QUEUE_PARSE);
    $file = new SplFileInfo($this->sourceFileDirectory . '/sample.php', '', '');
    $docblock_info = [
      'branch_id' => $default_branch->id(),
      'branch_type' => $default_branch->getEntityTypeId(),
      'action' => 'parse',
      'data' => $parser->parsePhp($parser->parseFile($file)) ?? [],
    ];
    $queue->createItem($docblock_info);
    $this->verifyCounts($counts, 1, 'Bad parse queue job added');
    $this->checkAndClearLog();
    $this->processApiParseQueue();
    $this->verifyCounts($counts, 0, 'Bad parse queue job processed');
    $this->checkAndClearLog();

    // Add the fake PHP branch.
    $this->createPhpBranchUi();
    $this->clearCache();
    $counts['api_php_branch'] = 1;
    $this->verifyCounts($counts, 0, 'Create PHP branch');

    // Parse and verify counts.
    $this->cronRun();
    $this->processApiParseQueue();
    $counts['api_php_branch_documentation'] = 2;
    $this->verifyCounts($counts, 0, 'Parse PHP branch');

    // Delete the branch and verify counts.
    $branches = PhpBranch::loadMultiple();
    foreach ($branches as $branch) {
      $this->drupalGet('admin/config/development/api/php_branch/' . $branch->id() . '/delete');
      $this->submitForm([], 'Delete');
    }
    $this->clearCache();
    $this->cronRun();
    $this->processApiDeleteQueue();
    $counts['api_php_branch'] = 0;
    $counts['api_php_branch_documentation'] = 0;
    $this->verifyCounts($counts, 0, 'Delete PHP branch');

    // Add the fake API branch.
    $this->createApiBranchUi();
    $this->clearCache();
    $counts['api_external_branch'] = 1;
    $this->verifyCounts($counts, 0, 'Create API branch');

    // Parse and verify counts.
    $this->cronRun();
    $this->processApiParseQueue();
    $counts['api_external_branch_documentation'] = 8;
    $this->verifyCounts($counts, 0, 'Parse API branch');

    // Delete the branch and verify counts.
    $branches = ExternalBranch::loadMultiple();
    foreach ($branches as $branch) {
      $this->drupalGet('admin/config/development/api/external_branch/' . $branch->id() . '/delete');
      $this->submitForm([], 'Delete');
    }
    $this->clearCache();
    $this->cronRun();
    $this->processApiDeleteQueue();
    $counts['api_external_branch'] = 0;
    $counts['api_external_branch_documentation'] = 0;
    $this->verifyCounts($counts, 0, 'Delete API branch');

    // Add and update the sample branch again, without excluding the
    // directory.
    $this->setUpBranchUi(NULL, TRUE, [
      'directory' => $this->sourceFileDirectory,
      'excluded' => '',
    ]);
    $this->clearCache();
    $this->cronRun();
    $this->processApiParseQueue();
    $counts['api_project'] = 1;
    $counts['api_branch'] = 1;
    $counts['api_branch_docblock'] = 80;
    $counts['api_branch_docblock_function'] = 34;
    $counts['api_branch_docblock_class_member'] = 26;
    $counts['api_branch_docblock_override'] = 23;
    $counts['api_branch_docblock_file'] = 12;
    $this->verifyCounts($counts, 0, 'Add and update branch with no exclusion, take 2');

    // Delete the project and verify counts.
    $default_branch = $this->getBranch();
    $this->drupalGet('admin/config/development/api/project/' . $default_branch->getProject()->id() . '/delete');
    $this->submitForm([], 'Delete');
    $this->clearCache();
    $this->cronRun();
    $this->processApiDeleteQueue();
    $counts['api_branch'] = 0;
    $counts['api_project'] = 0;
    $counts['api_branch_docblock_file'] = 0;
    $counts['api_branch_docblock'] = 0;
    $counts['api_branch_docblock_function'] = 0;
    $counts['api_branch_docblock_class_member'] = 0;
    $counts['api_branch_docblock_override'] = 0;
    // At this point, make sure the reference storage table is cleared out
    // too. We haven't been tracking it.
    $counts['api_branch_docblock_reference'] = 0;
    $counts['api_branch_docblock_reference_count'] = 0;
    $this->verifyCounts($counts, 0, 'Project deleted');

    // Add both sample and fake PHP/API branches again.
    // Update the branches, but don't parse.
    $this->createPhpBranchUi();
    $this->createApiBranchUi();
    $this->setUpBranchUi(NULL, TRUE, [
      'directory' => $this->sourceFileDirectory,
    ]);
    $this->clearCache();
    $this->cronRun();

    // Disable and uninstall the API module. Verify counts.
    $this->uninstallApiModule();
    $counts = [];
    $this->verifyCounts($counts, 0, 'Uninstalled');

    // Verify that there are no auto-complete files left over.
    $this->assertFalse(is_dir('public://api'), 'API files directory is empty');
  }

  /**
   * Recursively copies files from a source to a destination directory.
   *
   * Slightly modified (variable names and coding standards) from a comment
   * on http://php.net/manual/en/function.copy.php .
   *
   * @param string $source
   *   Source directory to copy.
   * @param string $destination
   *   Desintation to copy to.
   */
  protected static function recursiveCopyFiles($source, $destination) {
    $dir = opendir($source);
    @mkdir($destination);

    while (FALSE !== ($file = readdir($dir))) {
      if (($file != '.') && ($file != '..')) {
        if (is_dir($source . '/' . $file)) {
          self::recursiveCopyFiles($source . '/' . $file, $destination . '/' . $file);
        }
        else {
          copy($source . '/' . $file, $destination . '/' . $file);
        }
      }
    }
    closedir($dir);
  }

}

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

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