Skip to content
WebTestBase.php 130 KiB
Newer Older
 * Definition of \Drupal\simpletest\WebTestBase.
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Database\Database;
use Drupal\Core\Database\ConnectionNotDefinedException;
use Drupal\Core\Language\Language;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Session\UserSession;
use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\Core\Datetime\DrupalDateTime;
use Symfony\Component\HttpFoundation\Request;
  /**
   * The profile to install as a basis for testing.
   *
   * @var string
   */
  protected $profile = 'testing';
  /**
   * The URL currently loaded in the internal browser.
   *
   * @var string
   */
  protected $url;

  /**
   * The handle of the current cURL connection.
   *
   * @var resource
   */
  protected $curlHandle;

  /**
   * The headers of the page currently loaded in the internal browser.
   *
   * @var Array
   */
  protected $headers;

  /**
   * Indicates that headers should be dumped if verbose output is enabled.
   *
   * Headers are dumped to verbose by drupalGet(), drupalHead(), and
  /**
   * The content of the page currently loaded in the internal browser.
   *
   * @var string
   */
  protected $content;

  /**
   * The plain-text content of the currently-loaded page.
   * The value of drupalSettings for the currently-loaded page.
   * drupalSettings refers to the drupalSettings JavaScript variable.
   */
  protected $elements = NULL;

  /**
   * The current user logged in using the internal browser.
   *
   * @var bool
   */
  protected $loggedInUser = FALSE;

  /**
   * The current cookie file used by cURL.
   *
   * We do not reuse the cookies in further runs, so we do not need a file
   * but we still need cookie handling, so we set the jar to NULL.
   */
  protected $cookieFile = NULL;

  /**
   * Additional cURL options.
   *
   * \Drupal\simpletest\WebTestBase itself never sets this but always obeys what
   * is set.
   * The original user, before it was changed to a clean uid = 1 for testing.
   * The original shutdown handlers array, before it was cleaned for testing.
   *
   * @var array
   */
  protected $originalShutdownCallbacks = array();

  /**
   * HTTP authentication credentials (<username>:<password>).
   */
  protected $httpauth_credentials = NULL;

  /**
   * The current session name, if available.
   */
  protected $session_name = NULL;

  /**
   * The current session ID, if available.
   */
  protected $session_id = NULL;

  /**
   * Whether the files were copied to the test files directory.
   */
  protected $generatedTestFiles = FALSE;

  /**
   * The maximum number of redirects to follow when handling responses.
   */
  protected $maximumRedirects = 5;

  /**
   * The number of redirects followed during the handling of a request.
   */
  protected $redirect_count;

  /**
   * Cookies to set on curl requests.
   *
   * @var array
   */
  protected $curlCookies = array();

  /**
   * An array of custom translations suitable for drupal_rewrite_settings().
   *
   * @var array
   */
  protected $customTranslations;

   * Constructor for \Drupal\simpletest\WebTestBase.
   */
  function __construct($test_id = NULL) {
    parent::__construct($test_id);
    $this->skipClasses[__CLASS__] = TRUE;
  }

  /**
   * Get a node from the database based on its title.
   *
   *   A node title, usually generated by $this->randomName().
   *   (optional) Whether to reset the entity cache.
   * @return \Drupal\Core\Entity\EntityInterface
   *   A node entity matching $title.
  function drupalGetNodeByTitle($title, $reset = FALSE) {
      \Drupal::entityManager()->getStorageController('node')->resetCache();
    }
    $nodes = entity_load_multiple_by_properties('node', array('title' => $title));
    // Load the first node returned from the database.
    $returned_node = reset($nodes);
    return $returned_node;
  }

  /**
   * Creates a node based on default settings.
   *
   * @param array $settings
   *   (optional) An associative array of settings for the node, as used in
   *   entity_create(). Override the defaults by specifying the key and value
   *   in the array, for example:
   *   @code
   *     $this->drupalCreateNode(array(
   *       'title' => t('Hello, world!'),
   *       'type' => 'article',
   *     ));
   *   @endcode
   *   The following defaults are provided:
   *   - body: Random string using the default filter format:
   *     @code
   *         'value' => $this->randomName(32),
   *         'format' => filter_default_format(),
   *       );
   *     @endcode
   *   - title: Random string.
   *   - changed: REQUEST_TIME.
   *   - promote: NODE_NOT_PROMOTED.
   *   - log: Empty string.
   *   - status: NODE_PUBLISHED.
   *   - sticky: NODE_NOT_STICKY.
   *   - type: 'page'.
   *   - langcode: Language::LANGCODE_NOT_SPECIFIED.
   *   - uid: The currently logged in user, or the user running test.
   *   - revision: 1. (Backwards-compatible binary flag indicating whether a
   *     new revision should be created; use 1 to specify a new revision.)
   *
   *   The created node entity.
   */
  protected function drupalCreateNode(array $settings = array()) {
    // Populate defaults array.
      'title'     => $this->randomName(8),
      'status'    => NODE_PUBLISHED,
      'sticky'    => NODE_NOT_STICKY,
      'langcode'  => Language::LANGCODE_NOT_SPECIFIED,

    // Use the original node's created time for existing nodes.
    if (isset($settings['created']) && !isset($settings['date'])) {
      $settings['date'] = format_date($settings['created'], 'custom', 'Y-m-d H:i:s O');

    // If the node's user uid is not specified manually, use the currently
    // logged in user if available, or else the user running the test.
    if (!isset($settings['uid'])) {
      if ($this->loggedInUser) {
        $settings['uid'] = $this->loggedInUser->id();
        $user = \Drupal::currentUser() ?: $GLOBALS['user'];
      'format' => filter_default_format(),
    $node = entity_create('node', $settings);
    if (!empty($settings['revision'])) {
      $node->setNewRevision();
    }

    return $node;
  }

  /**
   * Creates a custom content type based on default settings.
   *
   *   An array of settings to change from the defaults.
   *   Example: 'type' => 'foo'.
   * @return \Drupal\node\Entity\NodeType
  protected function drupalCreateContentType(array $values = array()) {
    // Find a non-existent random type name.
    if (!isset($values['type'])) {
      do {
        $id = strtolower($this->randomName(8));
      } while (node_type_load($id));
    }
    else {
      $id = $values['type'];
    }
    $values += array(
      'type' => $id,
      'name' => $id,
    $type = entity_create('node_type', $values);
    $status = $type->save();
    $this->assertEqual($status, SAVED_NEW, t('Created content type %type.', array('%type' => $type->id())));
    // Reset permissions so that permissions for this content type are
    // available.
  /**
   * Creates a block instance based on default settings.
   *
   * Note: Until this can be done programmatically, the active user account
   * must have permission to administer blocks.
   *
   * @param string $plugin_id
   *   The plugin ID of the block type for this block instance.
   * @param array $settings
   *   (optional) An associative array of settings for the block entity.
   *   Override the defaults by specifying the key and value in the array, for
   *   example:
   *   @code
   *     $this->drupalPlaceBlock('system_powered_by_block', array(
   *     ));
   *   @endcode
   *   The following defaults are provided:
   *
   * @todo
   *   Add support for creating custom block instances.
   */
  protected function drupalPlaceBlock($plugin_id, array $settings = array()) {
    $settings += array(
      'id' => strtolower($this->randomName(8)),
      'theme' => \Drupal::config('system.theme')->get('default'),
      'label' => $this->randomName(8),
      'visibility' => array(),
    foreach (array('region', 'id', 'theme', 'plugin', 'visibility', 'weight') as $key) {
      // Remove extra values that do not belong in the settings array.
      unset($settings[$key]);
    }
    $values['settings'] = $settings;
    $block = entity_create('block', $values);
    $block->save();
    return $block;
   * Gets a list files that can be used in tests.
   *   File type, possible values: 'binary', 'html', 'image', 'javascript',
   *   'php', 'sql', 'text'.
   * @param $size
   *   File size in bytes to match. Please check the tests/files folder.
   * @return
   *   List of files that match filter.
  protected function drupalGetTestFiles($type, $size = NULL) {
    if (empty($this->generatedTestFiles)) {
      // Generate binary test files.
      $lines = array(64, 1024);
      $count = 0;
      foreach ($lines as $line) {
        simpletest_generate_file('binary-' . $count++, 64, $line, 'binary');
      }

      // Generate text test files.
      $lines = array(16, 256, 1024, 2048, 20480);
      $count = 0;
      foreach ($lines as $line) {
        simpletest_generate_file('text-' . $count++, 64, $line);
      }

      // Copy other test files from simpletest.
      $original = drupal_get_path('module', 'simpletest') . '/files';
      $files = file_scan_directory($original, '/(html|image|javascript|php|sql)-.*/');
      foreach ($files as $file) {
        file_unmanaged_copy($file->uri, PublicStream::basePath());
      $this->generatedTestFiles = TRUE;
    }

    $files = array();
    // Make sure type is valid.
    if (in_array($type, array('binary', 'html', 'image', 'javascript', 'php', 'sql', 'text'))) {
      $files = file_scan_directory('public://', '/' . $type . '\-.*/');

      // If size is set then remove any files that are not of that size.
      if ($size !== NULL) {
        foreach ($files as $file) {
          }
        }
      }
    }
    usort($files, array($this, 'drupalCompareFiles'));
    return $files;
  }

  /**
   * Compare two files based on size and file name.
  protected function drupalCompareFiles($file1, $file2) {
    $compare_size = filesize($file1->uri) - filesize($file2->uri);
    if ($compare_size) {
      // Sort by file size.
      return $compare_size;
      // The files were the same size, so sort alphabetically.
      return strnatcmp($file1->name, $file2->name);
   * Create a user with a given set of permissions.
   * @param array $permissions
   *   Array of permission names to assign to user. Note that the user always
   *   has the default permissions derived from the "authenticated users" role.
   * @return \Drupal\user\Entity\User|false
   *   A fully loaded user object with pass_raw property, or FALSE if account
  protected function drupalCreateUser(array $permissions = array(), $name = NULL) {
    // Create a role with the given permission set, if any.
    $rid = FALSE;
    if ($permissions) {
      $rid = $this->drupalCreateRole($permissions);
      if (!$rid) {
        return FALSE;
      }
    }

    // Create a user assigned to that role.
    $edit = array();
    $edit['name']   = !empty($name) ? $name : $this->randomName();
    $edit['mail']   = $edit['name'] . '@example.com';
    $edit['pass']   = user_password();
    $edit['status'] = 1;
    $account = entity_create('user', $edit);
    $account->save();
    $this->assertTrue($account->id(), String::format('User created with name %name and pass %pass', array('%name' => $edit['name'], '%pass' => $edit['pass'])), 'User login');
    if (!$account->id()) {
      return FALSE;
    }

    // Add the raw password so that we can log in as this user.
    $account->pass_raw = $edit['pass'];
    return $account;
  }

  /**
   * Internal helper function; Create a role with specified permissions.
   *
   *   Array of permission names to assign to role.
   * @param string $rid
   *   (optional) The role ID (machine name). Defaults to a random name.
   * @param string $name
   *   (optional) The label for the role. Defaults to a random string.
   * @param integer $weight
   *   (optional) The weight for the role. Defaults NULL so that entity_create()
   *   sets the weight to maximum + 1.
   *   Role ID of newly created role, or FALSE if role creation failed.
  protected function drupalCreateRole(array $permissions, $rid = NULL, $name = NULL, $weight = NULL) {
    // Generate a random, lowercase machine name if none was passed.
    if (!isset($rid)) {
      $rid = strtolower($this->randomName(8));
    }
    // Generate a random label.
    if (!isset($name)) {
      // In the role UI role names are trimmed and random string can start or
      // end with a space.
      $name = trim($this->randomString(8));
    // Check the all the permissions strings are valid.
    if (!$this->checkPermissions($permissions)) {
      return FALSE;
    }

    $role = entity_create('user_role', array(
      'id' => $rid,
      'label' => $name,
    ));
    if (!is_null($weight)) {
      $role->set('weight', $weight);
    }
    $result = $role->save();

    $this->assertIdentical($result, SAVED_NEW, t('Created role ID @rid with name @name.', array(
      '@name' => var_export($role->label(), TRUE),
      '@rid' => var_export($role->id(), TRUE),
    )), t('Role'));

    if ($result === SAVED_NEW) {
      // Grant the specified permissions to the role, if any.
      if (!empty($permissions)) {
        user_role_grant_permissions($role->id(), $permissions);
        $assigned_permissions = entity_load('user_role', $role->id())->permissions;
        $missing_permissions = array_diff($permissions, $assigned_permissions);
        if (!$missing_permissions) {
          $this->pass(t('Created permissions: @perms', array('@perms' => implode(', ', $permissions))), t('Role'));
        }
        else {
          $this->fail(t('Failed to create permissions: @perms', array('@perms' => implode(', ', $missing_permissions))), t('Role'));
        }
      }
  /**
   * Check to make sure that the array of permissions are valid.
   *
   * @param $permissions
   *   Permissions to check.
   * @param $reset
   *   Reset cached available permissions.
   * @return
   *   TRUE or FALSE depending on whether the permissions are valid.
  protected function checkPermissions(array $permissions, $reset = FALSE) {
    $available = &drupal_static(__FUNCTION__);
      $available = array_keys(module_invoke_all('permission'));
    }

    $valid = TRUE;
    foreach ($permissions as $permission) {
      if (!in_array($permission, $available)) {
        $this->fail(t('Invalid permission %permission.', array('%permission' => $permission)), t('Role'));
        $valid = FALSE;
      }
    }
    return $valid;
  }

   * Log in a user with the internal browser.
   *
   * If a user is already logged in, then the current user is logged out before
   * logging in the specified user.
   *
   * Please note that neither the global $user nor the passed-in user object is
   * populated with data of the logged in user. If you need full access to the
   * user object after logging in, it must be updated manually. If you also need
   * access to the plain-text password of the user (set by drupalCreateUser()),
   * e.g. to log in the same user again, then it must be re-assigned manually.
   * For example:
   * @code
   *   // Create a user.
   *   $account = $this->drupalCreateUser(array());
   *   $this->drupalLogin($account);
   *   // Load real user object.
   *   $pass_raw = $account->pass_raw;
   *   $account->pass_raw = $pass_raw;
   * @endcode
   * @param \Drupal\Core\Session\AccountInterface $account
   *   User object representing the user to log in.
  protected function drupalLogin(AccountInterface $account) {
      'name' => $account->getUsername(),
    $this->drupalPostForm('user', $edit, t('Log in'));
    // @see WebTestBase::drupalUserIsLoggedIn()
    if (isset($this->session_id)) {
      $account->session_id = $this->session_id;
    $pass = $this->assert($this->drupalUserIsLoggedIn($account), format_string('User %name successfully logged in.', array('%name' => $account->getUsername())), 'User login');
      $this->container->set('current_user', $account);
  /**
   * Returns whether a given user account is logged in.
   *
   * @param \Drupal\user\UserInterface $account
   *   The user account object to check.
   */
  protected function drupalUserIsLoggedIn($account) {
    if (!isset($account->session_id)) {
      return FALSE;
    }
    // @see _drupal_session_read()
    return (bool) db_query("SELECT sid FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = :sid", array(':sid' => $account->session_id))->fetchField();
  }

  /**
   * Generate a token for the currently logged in user.
   */
  protected function drupalGetToken($value = '') {
    $private_key = drupal_get_private_key();
    return Crypt::hmacBase64($value, $this->session_id . $private_key);
  /**
   * Logs a user out of the internal browser and confirms.
   *
   * Confirms logout by checking the login page.
  protected function drupalLogout() {
    // Make a request to the logout page, and redirect to the user page, the
    // idea being if you were properly logged out you should be seeing a login
    // screen.
    $this->drupalGet('user/logout', array('query' => array('destination' => 'user')));
    $this->assertResponse(200, 'User was logged out.');
    $pass = $this->assertField('name', 'Username field found.', 'Logout');
    $pass = $pass && $this->assertField('pass', 'Password field found.', 'Logout');
      // @see WebTestBase::drupalUserIsLoggedIn()
      unset($this->loggedInUser->session_id);
      $this->container->set('current_user', drupal_anonymous_user());
  /**
   * Sets up a Drupal site for running functional and integration tests.
   *
   * Generates a random database prefix and installs Drupal with the specified
   * installation profile in \Drupal\simpletest\WebTestBase::$profile into the
   * prefixed database. Afterwards, installs any additional modules specified by
   * the test.
   *
   * After installation all caches are flushed and several configuration values
   * are reset to the values of the parent site executing the test, since the
   * default values may be incompatible with the environment in which tests are
   * being executed.
   *
   * @param ...
   *   List of modules to enable for the duration of the test. This can be
   *   either a single array or a variable number of string arguments.
   *
   * @see \Drupal\simpletest\WebTestBase::prepareDatabasePrefix()
   * @see \Drupal\simpletest\WebTestBase::changeDatabasePrefix()
   * @see \Drupal\simpletest\WebTestBase::prepareEnvironment()
   */
  protected function setUp() {
    // When running tests through the Simpletest UI (vs. on the command line),
    // Simpletest's batch conflicts with the installer's batch. Batch API does
    // not support the concept of nested batches (in which the nested is not
    // progressive), so we need to temporarily pretend there was no batch.
    // Backup the currently running Simpletest batch.
    $this->originalBatch = batch_get();

    // Create the database prefix for this test.
    $this->prepareDatabasePrefix();

    // Prepare the environment for running tests.
    $this->prepareEnvironment();
    if (!$this->setupEnvironment) {
      return FALSE;
    }
    // Reset all statics and variables to perform tests in a clean environment.
    $conf = array();
    drupal_static_reset();

    // Change the database prefix.
    // All static variables need to be reset before the database prefix is
    // changed, since \Drupal\Core\Utility\CacheArray implementations attempt to
    // write back to persistent caches when they are destructed.
    $this->changeDatabasePrefix();
    if (!$this->setupDatabasePrefix) {
      return FALSE;
    }
    // Set the 'simpletest_parent_profile' variable to add the parent profile's
    // search path to the child site's search paths.
    // @see drupal_system_listing()
    $conf['simpletest_parent_profile'] = $this->originalProfile;

    $this->root_user = new UserSession(array(
      'name' => 'admin',
      'mail' => 'admin@example.com',
      'pass_raw' => $this->randomName(),

    // Reset the static batch to remove Simpletest's batch operations.
    $batch = &batch_get();
    $batch = array();
    $variable_groups = array(
      'system.file' => array(
        'path.private' =>  $this->private_files_directory,
        'path.temporary' =>  $this->temp_files_directory,
      ),
      'locale.settings' =>  array(
        'translation.path' => $this->translation_files_directory,
      ),
    foreach ($variable_groups as $config_base => $variables) {
      foreach ($variables as $name => $value) {
        NestedArray::setValue($GLOBALS['conf'], array_merge(array($config_base), explode('.', $name)), $value);
      }
    $this->settingsSet('file_public_path', $this->public_files_directory);
    // Execute the non-interactive installer.
    require_once DRUPAL_ROOT . '/core/includes/install.core.inc';
    $this->settingsSet('cache', array('default' => 'cache.backend.memory'));
    $parameters = $this->installParameters();
    install_drupal($parameters);

    // Set the install_profile so that web requests to the requests to the child
    // site have the correct profile.
    $settings = array(
      'settings' => array(
        'install_profile' => (object) array(
          'value' => $this->profile,
          'required' => TRUE,
        ),
      ),
    );
    $this->writeSettings($settings);
    // Override install profile in Settings to so the correct profile is used by
    // tests.
    $this->settingsSet('install_profile', $this->profile);

    $this->settingsSet('cache', array());

    // Restore the original Simpletest batch.
    $batch = &batch_get();
    $batch = $this->originalBatch;
    // Set 'parent_profile' of simpletest to add the parent profile's
    // search path to the child site's search paths.
    // @see drupal_system_listing()
    \Drupal::config('simpletest.settings')->set('parent_profile', $this->originalProfile)->save();
    // Collect modules to install.
    $class = get_class($this);
    while ($class) {
      if (property_exists($class, 'modules')) {
        $modules = array_merge($modules, $class::$modules);
      }
      $class = get_parent_class($class);
    }
      $success = \Drupal::moduleHandler()->install($modules, TRUE);
      $this->assertTrue($success, t('Enabled modules: %modules', array('%modules' => implode(', ', $modules))));
    // Reset/rebuild all data structures after enabling the modules.
    $this->resetAll();
    // Now make sure that the file path configurations are saved. This is done
    // after we install the modules to override default values.
    foreach ($variable_groups as $config_base => $variables) {
      foreach ($variables as $name => $value) {
        $config->set($name, $value);
      }
      $config->save();
    }

    // Use the test mail class instead of the default mail handler class.
    \Drupal::config('system.mail')->set('interface.default', 'Drupal\Core\Mail\VariableLog')->save();
    drupal_set_time_limit($this->timeLimit);
    // Temporary fix so that when running from run-tests.sh we don't get an
    // empty current path which would indicate we're on the home page.
    $path = current_path();
    if (empty($path)) {
      _current_path('run-tests');
    }
  /**
   * Returns the parameters that will be used when Simpletest installs Drupal.
   *
   * @see install_drupal()
   * @see install_state_defaults()
   */
  protected function installParameters() {
    $connection_info = Database::getConnectionInfo();
    $parameters = array(
      'interactive' => FALSE,
      'parameters' => array(
        'profile' => $this->profile,
        'langcode' => 'en',
      ),
      'forms' => array(
        'install_settings_form' => $connection_info['default'],
        'install_configure_form' => array(
          'site_name' => 'Drupal',
          'site_mail' => 'simpletest@example.com',
          'account' => array(
            'name' => $this->root_user->name,
            'mail' => $this->root_user->getEmail(),
            'pass' => array(
              'pass1' => $this->root_user->pass_raw,
              'pass2' => $this->root_user->pass_raw,
            ),
          ),
          // form_type_checkboxes_value() requires NULL instead of FALSE values
          // for programmatic form submissions to disable a checkbox.
          'update_status_module' => array(
            1 => NULL,
            2 => NULL,
          ),
        ),
      ),
    );
    return $parameters;
  }

  /**
   * Writes a test-specific settings.php file for the child site.
   *
   * The child site loads this after the parent site's settings.php, so settings
   * here override those.
   *
   * @param $settings An array of settings to write out, in the format expected
   *   by drupal_rewrite_settings().
   *
   * @see _drupal_load_test_overrides()
   * @see drupal_rewrite_settings()
   */
  protected function writeSettings($settings) {
    // drupal_rewrite_settings() sets the in-memory global variables in addition
    // to writing the file. We'll want to restore the original globals.
    foreach (array_keys($settings) as $variable_name) {
      $original_globals[$variable_name] = isset($GLOBALS[$variable_name]) ? $GLOBALS[$variable_name] : NULL;
    }

    include_once DRUPAL_ROOT . '/core/includes/install.inc';
    $filename = $this->public_files_directory . '/settings.php';
    file_put_contents($filename, "<?php\n");
    drupal_rewrite_settings($settings, $filename);

    // Restore the original globals.
    foreach ($original_globals as $variable_name => $value) {
      $GLOBALS[$variable_name] = $value;
    }
  }

  /**
   * Sets custom translations to the settings object and queues them to writing.
   *
   * In order for those custom translations to persist (being written in test
   * site's settings.php) make sure to also call self::writeCustomTranslations()
   *
   * @param string $langcode
   *   The langcode to add translations for.
   * @param array $values
   *   Array of values containing the untranslated string and its translation.
   *   For example:
   *   @code
   *   array(
   *     '' => array('Sunday' => 'domingo'),
   *     'Long month name' => array('March' => 'marzo'),
   *   );
   *   @endcode
   */
  protected function addCustomTranslations($langcode, array $values) {
    $this->settingsSet('locale_custom_strings_' . $langcode, $values);
    foreach ($values as $key => $translations) {
      foreach ($translations as $label => $value) {
        $this->customTranslations['locale_custom_strings_' . $langcode][$key][$label] = (object) array(
          'value' => $value,
          'required' => TRUE,
        );
      }
    }
  }

  /**
   * Writes custom translations to test site's settings.php.
   */
  protected function writeCustomTranslations() {
    $this->writeSettings(array('settings' => $this->customTranslations));
    $this->customTranslations = array();
  }

   * Overrides \Drupal\simpletest\TestBase::rebuildContainer().
   */
  protected function rebuildContainer() {
    parent::rebuildContainer();
    // Make sure the url generator has a request object, otherwise calls to
    // $this->drupalGet() will fail.
    $this->prepareRequestForGenerator();
  }

   * Resets all data structures after having enabled new modules.
   * This method is called by \Drupal\simpletest\WebTestBase::setUp() after
   * enabling the requested modules. It must be called again when additional
   * modules are enabled later.
   */
  protected function resetAll() {
    // Clear all database and static caches and rebuild data structures.
    drupal_flush_all_caches();
    $this->container = \Drupal::getContainer();

    // Reload global $conf array and permissions.
    $this->refreshVariables();
    $this->checkPermissions(array(), TRUE);
  }

   * Refreshes the in-memory set of variables.
   * Useful after a page request is made that changes a variable in a different
   * thread.
   * In other words calling a settings page with $this->drupalPostForm() with a
   * changed value would update a variable to reflect that change, but in the
   * thread that made the call (thread running the test) the changed variable
   * would not be picked up.
   *