diff --git a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php index f241069..18b3ae8 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php @@ -64,7 +64,9 @@ protected $keyValueFactory; /** - * A list of stream wrappers that have been registered by this test. + * A list of stream wrappers that have been registered for this test. + * + * @see \Drupal\simpletest\DrupalUnitTestBase::registerStreamWrapper() * * @var array */ @@ -141,9 +143,10 @@ protected function setUp() { // Tests based on DrupalUnitTestBase are entitled to use Drupal's File API. $this->registerStreamWrapper('public', 'Drupal\Core\StreamWrapper\PublicStream'); - // The private and temporary stream wrappers depend on configuration, but if - // System module was enabled, they can be registered. The test only needs - // to install System module's configuration. + + // The private and temporary stream wrappers depend on the system.file + // configuration. If System module was enabled, the test will most likely + // install System module's configuration, so we can register them here. if (in_array('system', $modules)) { $this->registerStreamWrapper('private', 'Drupal\Core\StreamWrapper\PrivateStream'); $this->registerStreamWrapper('temporary', 'Drupal\Core\StreamWrapper\TemporaryStream'); @@ -152,6 +155,10 @@ protected function setUp() { protected function tearDown() { $this->kernel->shutdown(); + // Before tearing down the test environment, ensure that no stream wrapper + // of this test leaks into the parent environment. Unlike all other global + // state variables in Drupal, stream wrappers are a global state construct + // of PHP core, which has to be maintained manually. foreach ($this->stream_wrappers as $scheme) { $this->unregisterStreamWrapper($scheme); } @@ -371,7 +378,12 @@ protected function registerStreamWrapper($scheme, $class, $type = STREAM_WRAPPER $this->unregisterStreamWrapper($scheme); } $this->stream_wrappers[$scheme] = $scheme; - stream_wrapper_register($scheme, $class); + if (($type & STREAM_WRAPPERS_LOCAL) == STREAM_WRAPPERS_LOCAL) { + stream_wrapper_register($scheme, $class); + } + else { + stream_wrapper_register($scheme, $class, STREAM_IS_URL); + } // @todo Revamp Drupal's stream wrapper API for D8. $wrappers = &drupal_static('file_get_stream_wrappers'); $wrappers[$scheme] = array( @@ -384,6 +396,9 @@ protected function registerStreamWrapper($scheme, $class, $type = STREAM_WRAPPER /** * Unregisters a stream wrapper previously registered by this test. * + * DrupalUnitTestBase::tearDown() automatically cleans up all registered + * stream wrappers, so this usually does not have to be called manually. + * * @param string $scheme * The scheme to unregister. */ diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php index a859d93..3bb6e3f 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php @@ -963,7 +963,14 @@ protected function prepareEnvironment() { // Create and set new configuration directories. $this->prepareConfigDirectories(); - // Unregister all Drupal stream wrappers. + // Unregister all custom stream wrappers of the parent site. + // Availability of Drupal stream wrappers varies by test base class: + // - UnitTestBase operates in a completely empty environment. + // - DrupalUnitTestBase supports and maintains stream wrappers in a custom + // way. + // - WebTestBase re-initializes Drupal stream wrappers are installation. + // The original stream wrappers are restored after the test run. + // @see TestBase::tearDown() $wrappers = file_get_stream_wrappers(); foreach ($wrappers as $scheme => $info) { stream_wrapper_unregister($scheme); @@ -1112,6 +1119,9 @@ protected function tearDown() { } } + // Delete temporary files directory. + file_unmanaged_delete_recursive($this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10), array($this, 'filePreDeleteCallback')); + // Restore original database connection. Database::removeConnection('default'); Database::renameConnection('simpletest_original_default', 'default'); @@ -1139,16 +1149,16 @@ protected function tearDown() { \Drupal::setContainer($this->originalContainer); $GLOBALS['config_directories'] = $this->originalConfigDirectories; - // Re-initialize original stream wrappers. + // Re-initialize original stream wrappers of the parent site. + // This must happen after static variables have been reset and the original + // container and $config_directories are restored, as simpletest_log_read() + // uses the public stream wrapper to locate the error.log. file_get_stream_wrappers(); // In case a fatal error occurred that was not in the test process read the // log to pick up any fatal errors. simpletest_log_read($this->testId, $this->databasePrefix, get_class($this), TRUE); - // Delete temporary files directory. - file_unmanaged_delete_recursive($this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10), array($this, 'filePreDeleteCallback')); - if (isset($this->originalPrefix)) { drupal_valid_test_ua($this->originalPrefix); }