+++ /dev/null
-<?php
-
-namespace Unish;
-
-use Webmozart\PathUtil\Path;
-
-/**
- * @group slow
- * @group commands
- */
-class UpdateDBTest extends CommandUnishTestCase
-{
- use TestModuleHelperTrait;
-
- protected $pathPostUpdate;
-
- public function testUpdateDBStatus()
- {
- $this->setUpDrupal(1, true);
- $this->drush('pm:enable', ['devel']);
- $this->drush('updatedb:status', [], ['format' => 'json']);
- $out = $this->getOutputFromJSON();
- $this->assertNull($out);
-
- // Force a pending update.
- $this->drush('php-script', ['updatedb_script'], ['script-path' => __DIR__ . '/resources']);
-
- // Assert that pending hook_update_n appears
- $this->drush('updatedb:status', [], ['format' => 'json']);
- $out = $this->getOutputFromJSON('devel_update_8002');
- $this->assertEquals('Add enforced dependencies to system.menu.devel', trim($out->description));
-
- // Run hook_update_n
- $this->drush('updatedb', []);
-
- // Assert that we ran hook_update_n properly
- $this->drush('updatedb:status', [], ['format' => 'json']);
- $out = $this->getOutputFromJSON();
- $this->assertNull($out);
-
- // Assure that a pending post-update is reported.
- $this->pathPostUpdate = $this->getSut() . '/web/modules/unish/devel/devel.post_update.php';
- copy(__DIR__ . '/resources/devel.post_update.php', $this->pathPostUpdate);
- $this->drush('updatedb:status', [], ['format' => 'json']);
- $out = $this->getOutputFromJSON('devel-post-null_op');
- $this->assertEquals('This is a test of the emergency broadcast system.', trim($out->description));
- }
-
- /**
- * Tests that updatedb command returns properly a failure.
- */
- public function testFailedUpdate()
- {
- $sites = $this->setUpDrupal(1, true);
- $options = [
- 'yes' => null,
- 'root' => $this->webroot(),
- 'uri' => key($sites),
- ];
- $this->setupModulesForTests(['woot'], Path::join(__DIR__, 'resources/modules/d8'));
- $this->drush('pm-enable', ['woot'], $options);
-
- // Force a pending update.
- $this->drush('php-script', ['updatedb_script'], ['script-path' => __DIR__ . '/resources']);
-
- // Force re-run of woot_update_8101().
- $this->drush('php:eval', array('drupal_set_installed_schema_version("woot", 8100)'), $options);
-
- // Force re-run of the post-update woot_post_update_failing().
- $this->forcePostUpdate('woot_post_update_failing', $options);
-
- // Run updates.
- $this->drush('updatedb', [], $options, null, null, self::EXIT_ERROR);
-
- $expected_output = <<<LOG
- -------- ----------- --------------- -----------------------
- Module Update ID Type Description
- -------- ----------- --------------- -----------------------
- woot 8101 hook_update_n Good update.
- woot 8102 hook_update_n Failing update.
- woot 8103 hook_update_n Another good update.
- woot failing post-update Failing post-update.
- -------- ----------- --------------- -----------------------
-
- // Do you wish to run the specified pending updates?: yes.
-LOG;
- $this->assertOutputEquals(preg_replace('# *#', ' ', $this->simplifyOutput($expected_output)));
-
- $expected_error_output = <<<LOG
- [notice] Update started: woot_update_8101
- [notice] This is the update message from woot_update_8101
- [ok] Update completed: woot_update_8101
- [notice] Update started: woot_update_8102
- [error] This is the exception message thrown in woot_update_8102
- [error] Update failed: woot_update_8102
- [error] Update aborted by: woot_update_8102
- [error] Finished performing updates.
-LOG;
-
- $this->assertErrorOutputEquals(preg_replace('# *#', ' ', $this->simplifyOutput($expected_error_output)));
- }
-
- /**
- * Tests that a failed post-update is handled correctly.
- */
- public function testFailedPostUpdate()
- {
- $sites = $this->setUpDrupal(1, true);
- $options = [
- 'yes' => null,
- 'root' => $this->webroot(),
- 'uri' => key($sites),
- ];
- $this->setupModulesForTests(['woot'], Path::join(__DIR__, 'resources/modules/d8'));
- $this->drush('pm-enable', ['woot'], $options);
-
- // Force re-run of woot_update_8103().
- $this->drush('php:eval', array('drupal_set_installed_schema_version("woot", 8102)'), $options);
-
- // Force re-run of post-update hooks.
- $this->forcePostUpdate('woot_post_update_a', $options);
- $this->forcePostUpdate('woot_post_update_failing', $options);
-
- // Run updates.
- $this->drush('updatedb', [], $options, null, null, self::EXIT_ERROR);
-
- $expected_output = <<<LOG
- -------- ----------- --------------- -------------------------
- Module Update ID Type Description
- -------- ----------- --------------- -------------------------
- woot 8103 hook_update_n Another good update.
- woot a post-update Successful post-update.
- woot failing post-update Failing post-update.
- -------- ----------- --------------- -------------------------
-
- // Do you wish to run the specified pending updates?: yes.
-LOG;
- $this->assertOutputEquals(preg_replace('# *#', ' ', $this->simplifyOutput($expected_output)));
-
- $expected_error_output = <<<LOG
- [notice] Update started: woot_update_8103
- [notice] This is the update message from woot_update_8103
- [ok] Update completed: woot_update_8103
- [notice] Update started: woot_post_update_a
- [notice] This is the update message from woot_post_update_a
- [ok] Update completed: woot_post_update_a
- [notice] Update started: woot_post_update_failing
- [error] This is the exception message thrown in woot_post_update_failing
- [error] Update failed: woot_post_update_failing
- [error] Update aborted by: woot_post_update_failing
- [error] Finished performing updates.
-LOG;
-
- $this->assertErrorOutputEquals(preg_replace('# *#', ' ', $this->simplifyOutput($expected_error_output)));
- }
-
- /**
- * Tests that the updatedb command works when new services are introduced.
- *
- * This is a regression test for a bug that prevented the updatedb command
- * from running when the update introduces a new module, and introduces a
- * new service in an existing module that has a dependency on the new
- * module.
- *
- * @see https://github.com/drush-ops/drush/issues/3193
- * @see https://www.drupal.org/project/drupal/issues/2863986
- */
- public function testUpdateModuleWithServiceDependency()
- {
- $root = $this->webroot();
- $sites = $this->setUpDrupal(1, true);
- $options = [
- 'yes' => null,
- 'root' => $root,
- 'uri' => key($sites),
- 'include' => __DIR__,
- ];
- $this->setupModulesForTests(['woot'], Path::join(__DIR__, 'resources/modules/d8'));
- $this->drush('pm-enable', ['woot'], $options);
-
- // Force re-run of the post-update woot_post_update_install_devel().
- $this->forcePostUpdate('woot_post_update_install_devel', $options);
-
- // Force a flush of the dependency injection container, so that we can
- // test that the container can be correctly rebuilt even if new services
- // are introduced that depend on modules that are not enabled yet.
- $this->drush('unit-invalidate-container', [], $options);
-
- // Introduce a new service in the Woot module that depends on a service
- // in the Devel module (which is not yet enabled).
- $filename = Path::join($root, 'modules/unish/woot/woot.services.yml');
- $serviceDefinition = <<<YAML_FRAGMENT
- woot.depending_service:
- class: Drupal\woot\DependingService
- arguments: ['@devel.dumper']
-YAML_FRAGMENT;
- file_put_contents($filename, $serviceDefinition, FILE_APPEND);
-
- $filename = Path::join($root, 'modules/unish/woot/woot.info.yml');
- $moduleDependency = <<<YAML_FRAGMENT
-dependencies:
- - devel
-YAML_FRAGMENT;
- file_put_contents($filename, $moduleDependency, FILE_APPEND);
-
- // Run updates.
- $this->drush('updatedb');
-
- // Assert that the updates were run correctly.
- $this->drush('updatedb:status', [], ['format' => 'json']);
- $out = $this->getOutputFromJSON();
- $this->assertNull($out);
- }
-
- /**
- * Tests that updates and post-updated can be executed successfully.
- */
- public function testSuccessfulUpdate()
- {
- $sites = $this->setUpDrupal(1, true);
- $options = [
- 'yes' => null,
- 'root' => $this->webroot(),
- 'uri' => key($sites),
- ];
- $this->setupModulesForTests(['woot'], Path::join(__DIR__, 'resources/modules/d8'));
- $this->drush('pm-enable', ['woot'], $options);
-
- // Force re-run of woot_update_8103() which is expected to be completed successfully.
- $this->drush('php:eval', array('drupal_set_installed_schema_version("woot", 8102)'), $options);
-
- // Force re-run of post-update hooks which are expected to be completed successfully.
- $this->forcePostUpdate('woot_post_update_a', $options);
- $this->forcePostUpdate('woot_post_update_render', $options);
-
- // Run updates.
- $this->drush('updatedb', [], $options, null, null, self::EXIT_SUCCESS);
-
- $expected_output = <<<LOG
- -------- ----------- --------------- -------------------------
- Module Update ID Type Description
- -------- ----------- --------------- -------------------------
- woot 8103 hook_update_n Another good update.
- woot a post-update Successful post-update.
- woot render post-update Renders some content.
- -------- ----------- --------------- -------------------------
-
- // Do you wish to run the specified pending updates?: yes.
-LOG;
- $this->assertOutputEquals(preg_replace('# *#', ' ', $this->simplifyOutput($expected_output)));
-
- $expected_error_output = <<<LOG
- [notice] Update started: woot_update_8103
- [notice] This is the update message from woot_update_8103
- [ok] Update completed: woot_update_8103
- [notice] Update started: woot_post_update_a
- [notice] This is the update message from woot_post_update_a
- [ok] Update completed: woot_post_update_a
- [notice] Update started: woot_post_update_render
- [ok] Update completed: woot_post_update_render
- [success] Finished performing updates.
-LOG;
-
- $this->assertErrorOutputEquals(preg_replace('# *#', ' ', $this->simplifyOutput($expected_error_output)));
- }
-
- public function tearDown()
- {
- $this->recursiveDelete($this->pathPostUpdate, true);
- parent::tearDown();
- }
-
- /**
- * Forces a post-update hook to run again on the next database update.
- *
- * @param string $hook
- * The name of the hook that needs to be run again.
- * @param array $options
- * An associative array containing options for the `sql:query` command.
- */
- protected function forcePostUpdate($hook, array $options)
- {
- $this->drush('sql:query', ["SELECT value FROM key_value WHERE collection = 'post_update' AND name = 'existing_updates'"], $options);
- $functions = unserialize($this->getOutput());
- unset($functions[array_search($hook, $functions)]);
- $functions = serialize($functions);
- $this->drush('sql:query', ["UPDATE key_value SET value = '$functions' WHERE collection = 'post_update' AND name = 'existing_updates'"], $options);
- }
-}