diff --git a/core/includes/batch.inc b/core/includes/batch.inc
index 0b07d8e..8d15213 100644
--- a/core/includes/batch.inc
+++ b/core/includes/batch.inc
@@ -52,6 +52,9 @@ function _batch_page() {
   // Retrieve the current state of the batch.
   if (!$batch) {
     $batch = batch_load($_REQUEST['id']);
+    debug($_REQUEST);
+    debug(drupal_get_token($_REQUEST['id']));
+    debug(db_query("SELECT token FROM {batch} WHERE bid = :bid", array(':bid' => $_REQUEST['id']))->fetchField());
     if (!$batch) {
       drupal_set_message(t('No active batch.'), 'error');
       drupal_goto();
@@ -454,6 +457,8 @@ function _batch_next_set() {
  */
 function _batch_finished() {
   $batch = &batch_get();
+  debug($batch);
+  error_log(var_export($batch, TRUE));
 
   // Execute the 'finished' callbacks for each batch set, if defined.
   foreach ($batch['sets'] as $batch_set) {
@@ -480,18 +485,17 @@ function _batch_finished() {
         $queue->deleteQueue();
       }
     }
+    // Clean-up the session. Not needed for CLI updates.
+    if (isset($_SESSION)) {
+      unset($_SESSION['batches'][$batch['id']]);
+      if (empty($_SESSION['batches'])) {
+        unset($_SESSION['batches']);
+      }
+    }
   }
   $_batch = $batch;
   $batch = NULL;
 
-  // Clean-up the session. Not needed for CLI updates.
-  if (isset($_SESSION)) {
-    unset($_SESSION['batches'][$batch['id']]);
-    if (empty($_SESSION['batches'])) {
-      unset($_SESSION['batches']);
-    }
-  }
-
   // Redirect if needed.
   if ($_batch['progressive']) {
     // Revert the 'destination' that was saved in batch_process().
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 95adc95..f1bb22e 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -2575,6 +2575,8 @@ function drupal_fast_404() {
  * Returns TRUE if a Drupal installation is currently being attempted.
  */
 function drupal_installation_attempted() {
+  return isset($GLOBALS['install_state']);
+  // @todo Entirely incompatible with non-interactive installer invoked from SimpleTest.
   return defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'install';
 }
 
diff --git a/core/includes/cache.inc b/core/includes/cache.inc
index 73bb05f..554fe95 100644
--- a/core/includes/cache.inc
+++ b/core/includes/cache.inc
@@ -24,13 +24,12 @@
  * @see Drupal\Core\Cache\CacheBackendInterface
  */
 function cache($bin = 'cache') {
+  $cache_objects = &drupal_static(__FUNCTION__, array());
+
   // Temporary backwards compatibiltiy layer, allow old style prefixed cache
   // bin names to be passed as arguments.
   $bin = str_replace('cache_', '', $bin);
 
-  // We do not use drupal_static() here because we do not want to change the
-  // storage of a cache bin mid-request.
-  static $cache_objects;
   if (!isset($cache_objects[$bin])) {
     $cache_backends = cache_get_backends();
     $class = isset($cache_backends[$bin]) ? $cache_backends[$bin] : $cache_backends['cache'];
diff --git a/core/includes/form.inc b/core/includes/form.inc
index 395cca7..dfc1cb5 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -3178,6 +3178,10 @@ function form_process_checkbox($element, $form_state) {
  * Processes a checkboxes form element.
  */
 function form_process_checkboxes($element) {
+  // The #type checkboxes element itself does not need validation.
+  // @todo Fix handling of values for checkboxes in programmed form submissions.
+  unset($element['#needs_validation']);
+
   $value = is_array($element['#value']) ? $element['#value'] : array();
   $element['#tree'] = TRUE;
   if (count($element['#options']) > 0) {
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 32ce838..84f98d9 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -224,7 +224,9 @@ function install_state_defaults() {
  */
 function install_begin_request(&$install_state) {
   // Add any installation parameters passed in via the URL.
-  $install_state['parameters'] += $_GET;
+  if ($install_state['interactive']) {
+    $install_state['parameters'] += $_GET;
+  }
 
   // Validate certain core settings that are used throughout the installation.
   if (!empty($install_state['parameters']['profile'])) {
@@ -240,11 +242,10 @@ function install_begin_request(&$install_state) {
   if (!$install_state['interactive']) {
     drupal_override_server_variables($install_state['server']);
   }
-
   // The user agent header is used to pass a database prefix in the request when
   // running tests. However, for security reasons, it is imperative that no
   // installation be permitted using such a prefix.
-  if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], "simpletest") !== FALSE) {
+  elseif (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], "simpletest") !== FALSE) {
     header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
     exit;
   }
@@ -459,6 +460,23 @@ function install_run_task($task, &$install_state) {
   }
 
   elseif ($task['type'] == 'batch') {
+    if (!$install_state['interactive']) {
+      $batch = $function($install_state);
+      if (!empty($batch['operations'])) {
+        // Build a dummy 'context' array to avoid exceptions.
+        $batch_context = array(
+          'sandbox'  => &$current_set['sandbox'],
+          'results'  => &$current_set['results'],
+          'finished' => &$finished,
+          'message'  => &$task_message,
+        );
+        foreach ($batch['operations'] as $operation) {
+          list($function, $args) = $operation;
+          call_user_func_array($function, array_merge($args, array(&$batch_context)));
+        }
+      }
+      return;
+    }
     // Start a new batch based on the task function, if one is not running
     // already.
     $current_batch = variable_get('install_current_batch');
@@ -1331,7 +1349,7 @@ function install_select_language(&$install_state) {
       }
       // One language, but not an interactive installation. Assume the user
       // knows what he is doing.
-      $langcode = current($files);
+      $file = current($files);
       $install_state['parameters']['langcode'] = $file->langcode;
       return;
     }
diff --git a/core/includes/install.inc b/core/includes/install.inc
index 41d244a..e47cd44 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -93,10 +93,10 @@ function drupal_load_updates() {
  * @see install_profile_info()
  */
 function drupal_install_profile_distribution_name() {
+  global $install_state;
   // During installation, the profile information is stored in the global
   // installation state (it might not be saved anywhere yet).
-  if (drupal_installation_attempted()) {
-    global $install_state;
+  if (isset($install_state['profile_info']['distribution_name'])) {
     return $install_state['profile_info']['distribution_name'];
   }
   // At all other times, we load the profile via standard methods.
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 3db5bbd..83c4483 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -3988,6 +3988,9 @@ function node_unpublish_by_keyword_action(Node $node, $context) {
  */
 function node_requirements($phase) {
   $requirements = array();
+  if ($phase !== 'runtime') {
+    return $requirements;
+  }
   // Ensure translations don't break at install time
   $t = get_t();
   // Only show rebuild button if there are either 0, or 2 or more, rows
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
index 6517bd1..586f634 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
@@ -150,15 +150,7 @@ abstract class TestBase {
     );
 
     // Store assertion for display after the test has completed.
-    try {
-      $connection = Database::getConnection('default', 'simpletest_original_default');
-    }
-    catch (ConnectionNotDefinedException $e) {
-      // If the test was not set up, the simpletest_original_default
-      // connection does not exist.
-      $connection = Database::getConnection('default', 'default');
-    }
-    $connection
+    self::getDatabaseConnection()
       ->insert('simpletest')
       ->fields($assertion)
       ->execute();
@@ -212,7 +204,8 @@ abstract class TestBase {
       'file' => $caller['file'],
     );
 
-    return db_insert('simpletest')
+    return self::getDatabaseConnection()
+      ->insert('simpletest')
       ->fields($assertion)
       ->execute();
   }
@@ -228,11 +221,24 @@ abstract class TestBase {
    * @see Drupal\simpletest\TestBase::insertAssert()
    */
   public static function deleteAssert($message_id) {
-    return (bool) db_delete('simpletest')
+    return (bool) self::getDatabaseConnection()
+      ->delete('simpletest')
       ->condition('message_id', $message_id)
       ->execute();
   }
 
+  public static function getDatabaseConnection() {
+    try {
+      $connection = Database::getConnection('default', 'simpletest_original_default');
+    }
+    catch (ConnectionNotDefinedException $e) {
+      // If the test was not set up, the simpletest_original_default
+      // connection does not exist.
+      $connection = Database::getConnection('default', 'default');
+    }
+    return $connection;
+  }
+
   /**
    * Cycles through backtrace until the first non-assertion method is found.
    *
@@ -593,6 +599,14 @@ abstract class TestBase {
       );
     }
     Database::addConnectionInfo('default', 'default', $connection_info['default']);
+
+    // Additionally override global $databases, since the installer does not use
+    // the Database connection info.
+    // @see install_verify_database_settings()
+    // @see install_database_errors()
+    // @todo Fix installer to use Database connection info.
+    global $databases;
+    $databases['default']['default'] = $connection_info['default'];
   }
 
   /**
@@ -623,6 +637,8 @@ abstract class TestBase {
     $this->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files');
     $this->originalProfile = drupal_get_profile();
     $this->originalUser = $user;
+//    $this->originalSession = isset($_SESSION) ? $_SESSION : NULL;
+    $this->originalGlobals = $GLOBALS;
 
     // Save and clean the shutdown callbacks array because it is static cached
     // and will be changed by the test run. Otherwise it will contain callbacks
@@ -692,6 +708,9 @@ abstract class TestBase {
     // Restore original database connection.
     Database::removeConnection('default');
     Database::renameConnection('simpletest_original_default', 'default');
+    global $databases;
+    $connection_info = Database::getConnectionInfo('default');
+    $databases['default']['default'] = $connection_info['default'];
 
     // Reset all static variables.
     drupal_static_reset();
@@ -714,6 +733,8 @@ abstract class TestBase {
 
     // Restore original user session.
     $user = $this->originalUser;
+//    $_SESSION = $this->originalSession;
+    $GLOBALS = $this->originalGlobals;
     drupal_save_session(TRUE);
   }
 
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 0856611..4ccc2b7 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -580,7 +580,16 @@ abstract class WebTestBase extends TestBase {
   protected function setUp() {
     global $user, $conf;
     $language_interface = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
-
+    //Get old batch id and token
+    $batch = batch_get();
+    if(!empty($batch['id'])) {
+      $this->batch_id = $batch['id'];
+      $this->old_token = drupal_get_token($this->batch_id);
+    }
+    else {
+      $this->batch_id = NULL;
+      $this->old_token = NULL;
+    }
     // Create the database prefix for this test.
     $this->prepareDatabasePrefix();
 
@@ -597,18 +606,99 @@ abstract class WebTestBase extends TestBase {
     // write back to persistent caches when they are destructed.
     $this->changeDatabasePrefix();
 
-    // Preset the 'install_profile' system variable, so the first call into
-    // system_rebuild_module_data() (in drupal_install_system()) will register
-    // the test's profile as a module. Without this, the installation profile of
-    // the parent site (executing the test) is registered, and the test
-    // profile's hook_install() and other hook implementations are never invoked.
-    $conf['install_profile'] = $this->profile;
-
-    // Perform the actual Drupal installation.
-    include_once DRUPAL_ROOT . '/core/includes/install.inc';
-    drupal_install_system();
+    // 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->preloadRegistry();
+    // Run the Drupal installer non-interactively.
+    // @see install.php, install.core.inc
+    require_once DRUPAL_ROOT . '/core/includes/install.core.inc';
+    $connection_info = Database::getConnectionInfo('default');
+    $this->root_user = (object) array(
+      'name' => 'admin',
+      'mail' => 'admin@example.com',
+      'pass_raw' => $this->randomName(),
+    );
+    $settings = array(
+      'interactive' => FALSE,
+      'parameters' => array(
+        'profile' => $this->profile,
+        'langcode' => 'en',
+      ),
+      'forms' => array(
+        'install_settings_form' => array(
+          'driver' => $connection_info['default']['driver'],
+          'username' => $connection_info['default']['username'],
+          'host' => $connection_info['default']['host'],
+          'port' => $connection_info['default']['port'],
+          'password' => $connection_info['default']['password'],
+          'database' => $connection_info['default']['database'],
+          'prefix' => $connection_info['default']['prefix'],
+        ),
+        'install_configure_form' => array(
+          'site_name' => 'Drupal',
+          'site_mail' => 'simpletest@example.com',
+          'account' => array(
+            'name' => $this->root_user->name,
+            'mail' => $this->root_user->mail,
+            'pass' => array(
+              'pass1' => $this->root_user->pass_raw,
+              'pass2' => $this->root_user->pass_raw,
+            ),
+          ),
+          'update_status_module' => array(
+            1 => FALSE,
+            2 => FALSE,
+          ),
+        ),
+      ),
+    );
+    // 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.
+//    $parent_batch = batch_get();
+
+//    $parent_session = $_SESSION;
+//    $parent_get = $_GET;
+
+    // Reset it and invoke the non-interactive installer.
+//    $batch = &batch_get();
+//    $batch = array();
+
+    // @todo The above has been replaced with changing install_run_task() in
+    //   install.core.inc to not invoke the Batch API at all for install tasks
+    //   of type 'batch'.
+
+    // @todo _batch_page() calls into batch_load() to reload the batch definition,
+    //   but that uses drupal_get_token() to validate that the batch belongs to
+    //   the current user. drupal_get_token() returns a different value after
+    //   test execution, so the batch finished page does not load.
+//    $session_id = session_id();
+    $originalSession = isset($_SESSION) ? $_SESSION : NULL;
+    $originalGlobals = $GLOBALS;
+    $request = request();
+    
+    install_drupal($settings);
+
+//    session_id($session_id);
+    $_SESSION = $originalSession;
+    $GLOBALS = $originalGlobals;
+    request($request);
+
+    // Restore the original Simpletest batch.
+//    $batch = &batch_get();
+//    $batch = $parent_batch;
+
+//    $_SESSION = $parent_session;
+//    $_GET = $parent_get;
+    // @todo Simpletest batch finishes, but redirects to /batch (which in turn
+    //   redirects to the front page, along with the message "No active batch."
+    //   -- something in the Drupal installer code seems to reset/erase the
+    //   Simpletest batch's ID or final redirection target.
+//    $this->verbose(var_export($batch, TRUE));
 
     // Set path variables.
     variable_set('file_public_path', $this->public_files_directory);
@@ -618,16 +708,8 @@ abstract class WebTestBase extends TestBase {
     // 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()
-    // @todo This may need to be primed like 'install_profile' above.
     variable_set('simpletest_parent_profile', $this->originalProfile);
 
-    // Include the testing profile.
-    variable_set('install_profile', $this->profile);
-    $profile_details = install_profile_info($this->profile, 'en');
-
-    // Install the modules specified by the testing profile.
-    module_enable($profile_details['dependencies'], FALSE);
-
     // Install modules needed for this test. This could have been passed in as
     // either a single array argument or a variable number of string arguments.
     // @todo Remove this compatibility layer in Drupal 8, and only accept
@@ -641,36 +723,15 @@ abstract class WebTestBase extends TestBase {
       $this->assertTrue($success, t('Enabled modules: %modules', array('%modules' => implode(', ', $modules))));
     }
 
-    // Run the profile tasks.
-    $install_profile_module_exists = db_query("SELECT 1 FROM {system} WHERE type = 'module' AND name = :name", array(
-      ':name' => $this->profile,
-    ))->fetchField();
-    if ($install_profile_module_exists) {
-      module_enable(array($this->profile), FALSE);
-    }
-
     // Reset/rebuild all data structures after enabling the modules.
     $this->resetAll();
 
-    // Run cron once in that environment, as install.php does at the end of
-    // the installation process.
-    drupal_cron_run();
-
     // Ensure that the session is not written to the new environment and replace
     // the global $user session with uid 1 from the new test site.
     drupal_save_session(FALSE);
     // Login as uid 1.
     $user = user_load(1);
 
-    // Restore necessary variables.
-    variable_set('install_task', 'done');
-    config('system.site')->set('mail', 'simpletest@example.com')->save();
-    variable_set('date_default_timezone', date_default_timezone_get());
-
-    // Set up English language.
-    unset($conf['language_default']);
-    $language_interface = language_default();
-
     // Use the test mail class instead of the default mail handler class.
     variable_set('mail_system', array('default-system' => 'Drupal\Core\Mail\VariableLog'));
 
@@ -679,42 +740,6 @@ abstract class WebTestBase extends TestBase {
   }
 
   /**
-   * Preload the registry from the testing site.
-   *
-   * This method is called by Drupal\simpletest\WebTestBase::setUp(), and preloads
-   * the registry from the testing site to cut down on the time it takes to
-   * set up a clean environment for the current test run.
-   */
-  protected function preloadRegistry() {
-    // Use two separate queries, each with their own connections: copy the
-    // {registry} and {registry_file} tables over from the parent installation
-    // to the child installation.
-    $original_connection = Database::getConnection('default', 'simpletest_original_default');
-    $test_connection = Database::getConnection();
-
-    foreach (array('registry', 'registry_file') as $table) {
-      // Find the records from the parent database.
-      $source_query = $original_connection
-        ->select($table, array(), array('fetch' => PDO::FETCH_ASSOC))
-        ->fields($table);
-
-      $dest_query = $test_connection->insert($table);
-
-      $first = TRUE;
-      foreach ($source_query->execute() as $row) {
-        if ($first) {
-          $dest_query->fields(array_keys($row));
-          $first = FALSE;
-        }
-        // Insert the records into the child database.
-        $dest_query->values($row);
-      }
-
-      $dest_query->execute();
-    }
-  }
-
-  /**
    * Reset all data structures after having enabled new modules.
    *
    * This method is called by Drupal\simpletest\WebTestBase::setUp() after enabling
@@ -789,6 +814,16 @@ abstract class WebTestBase extends TestBase {
 
     // Close the CURL handler.
     $this->curlClose();
+
+    if(!empty($this->batch_id)) {
+      //Regenerate batch token after install_drupal created a new session_id.
+      db_update('batch')
+        ->fields(array(
+          'token' => drupal_get_token($this->batch_id),
+        ))
+        ->condition('token', $this->old_token)
+        ->execute();
+    }
   }
 
   /**
