From ce2f16e1ad85626820c36870793f43a9e4e2b6af Mon Sep 17 00:00:00 2001
From: drugan <drugan@1578644.no-reply.drupal.org>
Date: Wed, 21 Dec 2016 19:32:07 +0200
Subject: [PATCH] Issue #2745123 by Mile23, drugan, slasher13, drunken monkey,
 Yogesh Pawar, blazey: Simpletest module crashes on cleanup,
 uninstall

---
 core/modules/simpletest/simpletest.module   |   24 +++++++++++++++++++-----
 core/modules/simpletest/src/TestBase.php    |   19 ++-----------------
 core/scripts/run-tests.sh                   |   11 +++++------
 core/tests/Drupal/Tests/BrowserTestBase.php |   22 ++--------------------
 4 files changed, 28 insertions(+), 48 deletions(-)

diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index f72ca5c..37b0e4e 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -674,14 +674,28 @@ function simpletest_clean_database() {
 /**
  * Finds all leftover temporary directories and removes them.
  */
-function simpletest_clean_temporary_directories() {
+function simpletest_clean_temporary_directories($directory = NULL) {
   $count = 0;
-  if (is_dir(DRUPAL_ROOT . '/sites/simpletest')) {
-    $files = scandir(DRUPAL_ROOT . '/sites/simpletest');
+  $root = \Drupal::root() . '/sites/simpletest/';
+  $dir = $directory ? explode('sites/simpletest/', $directory) : FALSE;
+
+  if (is_dir($root)) {
+    $files = !$dir ? scandir($root) : (isset($dir[1]) && is_dir("{$root}{$dir[1]}") ? [$dir[1]] : []);
     foreach ($files as $file) {
       if ($file[0] != '.') {
-        $path = DRUPAL_ROOT . '/sites/simpletest/' . $file;
-        file_unmanaged_delete_recursive($path, array('Drupal\simpletest\TestBase', 'filePreDeleteCallback'));
+        $path = "{$root}{$file}";
+        $result = file_unmanaged_delete_recursive($path, function ($any_path) {
+          // When the webserver runs with the same system user as the test
+          // runner, we can make read-only files writable again. If not, chmod
+          // will fail while the file deletion still works if file permissions
+          // have been configured correctly. Thus, we ignore any chmod errors.
+          @chmod($any_path, 0700);
+        });
+        if ($directory) {
+          // We do not need any more if this function was called from within a
+          // running test instead of using "Clean environment" button.
+          return $result;
+        }
         $count++;
       }
     }
diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php
index f4a23e7..e57de75 100644
--- a/core/modules/simpletest/src/TestBase.php
+++ b/core/modules/simpletest/src/TestBase.php
@@ -1363,8 +1363,8 @@ private function restoreEnvironment() {
     $this->container = $this->originalContainer;
     \Drupal::setContainer($this->originalContainer);
 
-    // Delete test site directory.
-    file_unmanaged_delete_recursive($this->siteDirectory, array($this, 'filePreDeleteCallback'));
+    // Delete the current test site directory.
+    simpletest_clean_temporary_directories($this->siteDirectory);
 
     // Restore original database connection.
     Database::removeConnection('default');
@@ -1525,21 +1525,6 @@ public static function generatePermutations($parameters) {
   }
 
   /**
-   * Ensures test files are deletable within file_unmanaged_delete_recursive().
-   *
-   * Some tests chmod generated files to be read only. During
-   * TestBase::restoreEnvironment() and other cleanup operations, these files
-   * need to get deleted too.
-   */
-  public static function filePreDeleteCallback($path) {
-    // When the webserver runs with the same system user as the test runner, we
-    // can make read-only files writable again. If not, chmod will fail while
-    // the file deletion still works if file permissions have been configured
-    // correctly. Thus, we ignore any problems while running chmod.
-    @chmod($path, 0700);
-  }
-
-  /**
    * Configuration accessor for tests. Returns non-overridden configuration.
    *
    * @param $name
diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index 2936723..f1a2d32 100755
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -862,7 +862,8 @@ function simpletest_script_cleanup($test_id, $test_class, $exitcode) {
   // Check whether a test site directory was setup already.
   // @see \Drupal\simpletest\TestBase::prepareEnvironment()
   $test_db = new TestDatabase($db_prefix);
-  $test_directory = DRUPAL_ROOT . '/' . $test_db->getTestSitePath();
+  $test_site = $test_db->getTestSitePath();
+  $test_directory = \Drupal::root() . '/' . $test_site;
   if (is_dir($test_directory)) {
     // Output the error_log.
     if (is_file($test_directory . '/error.log')) {
@@ -871,11 +872,9 @@ function simpletest_script_cleanup($test_id, $test_class, $exitcode) {
         $messages[] = $errors;
       }
     }
-    // Delete the test site directory.
-    // simpletest_clean_temporary_directories() cannot be used here, since it
-    // would also delete file directories of other tests that are potentially
-    // running concurrently.
-    file_unmanaged_delete_recursive($test_directory, array('Drupal\simpletest\TestBase', 'filePreDeleteCallback'));
+    // Delete the current test site directory leaving alone other tests that
+    // are potentially running concurrently.
+    simpletest_clean_temporary_directories($test_site);
     $messages[] = "- Removed test site directory.";
   }
 
diff --git a/core/tests/Drupal/Tests/BrowserTestBase.php b/core/tests/Drupal/Tests/BrowserTestBase.php
index 1306489..38d1906 100644
--- a/core/tests/Drupal/Tests/BrowserTestBase.php
+++ b/core/tests/Drupal/Tests/BrowserTestBase.php
@@ -520,24 +520,6 @@ protected function setUp() {
   }
 
   /**
-   * Ensures test files are deletable within file_unmanaged_delete_recursive().
-   *
-   * Some tests chmod generated files to be read only. During
-   * BrowserTestBase::cleanupEnvironment() and other cleanup operations,
-   * these files need to get deleted too.
-   *
-   * @param string $path
-   *   The file path.
-   */
-  public static function filePreDeleteCallback($path) {
-    // When the webserver runs with the same system user as phpunit, we can
-    // make read-only files writable again. If not, chmod will fail while the
-    // file deletion still works if file permissions have been configured
-    // correctly. Thus, we ignore any problems while running chmod.
-    @chmod($path, 0700);
-  }
-
-  /**
    * Clean up the Simpletest environment.
    */
   protected function cleanupEnvironment() {
@@ -555,8 +537,8 @@ protected function cleanupEnvironment() {
       }
     }
 
-    // Delete test site directory.
-    file_unmanaged_delete_recursive($this->siteDirectory, array($this, 'filePreDeleteCallback'));
+    // Delete the current test site directory.
+    simpletest_clean_temporary_directories($this->siteDirectory);
   }
 
   /**
-- 
1.7.9.5

