diff --git a/core/modules/simpletest/drupal_web_test_case.php b/core/modules/simpletest/drupal_web_test_case.php
index c9fc562..72c3bbb 100644
--- a/core/modules/simpletest/drupal_web_test_case.php
+++ b/core/modules/simpletest/drupal_web_test_case.php
@@ -1272,31 +1272,19 @@ class DrupalWebTestCase extends DrupalTestCase {
     }
   }
 
-  /**
-   * Generates a random database prefix, runs the install scripts on the
-   * prefixed database and enable the specified modules. After installation
-   * many caches are flushed and the internal browser is setup so that the
-   * page requests will run on the new prefix. A temporary files directory
-   * is created with the same name as the database prefix.
-   *
-   * @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.
-   */
-  protected function setUp() {
-    global $user, $language, $conf;
-
+  protected function prepareDatabasePrefix() {
     // Generate a temporary prefixed database to ensure that tests have a clean starting point.
     $this->databasePrefix = 'simpletest' . mt_rand(1000, 1000000);
     db_update('simpletest_test_id')
       ->fields(array('last_prefix' => $this->databasePrefix))
       ->condition('test_id', $this->testId)
       ->execute();
+  }
 
-    // Reset all statics and variables to perform tests in a clean environment.
-    $conf = array();
-    drupal_static_reset();
-
+  protected function changeDatabasePrefix() {
+    if (empty($this->databasePrefix)) {
+      $this->prepareDatabasePrefix();
+    }
     // Clone the current connection and replace the current prefix.
     $connection_info = Database::getConnectionInfo('default');
     Database::renameConnection('default', 'simpletest_original_default');
@@ -1307,12 +1295,24 @@ class DrupalWebTestCase extends DrupalTestCase {
     }
     Database::addConnectionInfo('default', 'default', $connection_info['default']);
 
+    // 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
+    // from both environments and the testing environment will try to call the
+    // handlers defined by the original one.
+    $callbacks = &drupal_register_shutdown_function();
+    $this->originalShutdownCallbacks = $callbacks;
+    $callbacks = array();
+  }
+
+  protected function prepareEnvironment() {
+    global $user, $language, $conf;
+
     // Store necessary current values before switching to prefixed database.
     $this->originalLanguage = $language;
     $this->originalLanguageDefault = variable_get('language_default');
     $this->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files');
     $this->originalProfile = drupal_get_profile();
-    $clean_url_original = variable_get('clean_url', 0);
+    $this->originalCleanUrl = variable_get('clean_url', 0);
 
     // Set to English to prevent exceptions from utf8_truncate() from t()
     // during install if the current language is not 'en'.
@@ -1325,30 +1325,46 @@ class DrupalWebTestCase extends DrupalTestCase {
       'weight' => 0,
     );
 
-    // Save and clean shutdown callbacks array because it static cached and
-    // will be changed by the test run. If we don't, then it will contain
-    // callbacks from both environments. So testing environment will try
-    // to call handlers from original environment.
-    $callbacks = &drupal_register_shutdown_function();
-    $this->originalShutdownCallbacks = $callbacks;
-    $callbacks = array();
-
     // Create test directory ahead of installation so fatal errors and debug
     // information can be logged during installation process.
     // Use temporary files directory with the same prefix as the database.
-    $public_files_directory  = $this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10);
-    $private_files_directory = $public_files_directory . '/private';
-    $temp_files_directory    = $private_files_directory . '/temp';
+    $this->public_files_directory  = $this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10);
+    $this->private_files_directory = $this->public_files_directory . '/private';
+    $this->temp_files_directory    = $this->private_files_directory . '/temp';
 
     // Create the directories
-    file_prepare_directory($public_files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
-    file_prepare_directory($private_files_directory, FILE_CREATE_DIRECTORY);
-    file_prepare_directory($temp_files_directory, FILE_CREATE_DIRECTORY);
+    file_prepare_directory($this->public_files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+    file_prepare_directory($this->private_files_directory, FILE_CREATE_DIRECTORY);
+    file_prepare_directory($this->temp_files_directory, FILE_CREATE_DIRECTORY);
     $this->generatedTestFiles = FALSE;
 
     // Log fatal errors.
     ini_set('log_errors', 1);
-    ini_set('error_log', $public_files_directory . '/error.log');
+    ini_set('error_log', $this->public_files_directory . '/error.log');
+  }
+
+  /**
+   * Generates a random database prefix, runs the install scripts on the
+   * prefixed database and enable the specified modules. After installation
+   * many caches are flushed and the internal browser is setup so that the
+   * page requests will run on the new prefix. A temporary files directory
+   * is created with the same name as the database prefix.
+   *
+   * @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.
+   */
+  protected function setUp() {
+    global $user, $language, $conf;
+
+    $this->prepareDatabasePrefix();
+    $this->changeDatabasePrefix();
+
+    // Reset all statics and variables to perform tests in a clean environment.
+    $conf = array();
+    drupal_static_reset();
+
+    $this->prepareEnvironment();
 
     // Set the test information for use in other parts of Drupal.
     $test_info = &$GLOBALS['drupal_test_info'];
@@ -1368,9 +1384,9 @@ class DrupalWebTestCase extends DrupalTestCase {
     $this->preloadRegistry();
 
     // Set path variables.
-    variable_set('file_public_path', $public_files_directory);
-    variable_set('file_private_path', $private_files_directory);
-    variable_set('file_temporary_path', $temp_files_directory);
+    variable_set('file_public_path', $this->public_files_directory);
+    variable_set('file_private_path', $this->private_files_directory);
+    variable_set('file_temporary_path', $this->temp_files_directory);
 
     // Set the 'simpletest_parent_profile' variable to add the parent profile's
     // search path to the child site's search paths.
@@ -1420,7 +1436,7 @@ class DrupalWebTestCase extends DrupalTestCase {
 
     // Restore necessary variables.
     variable_set('install_task', 'done');
-    variable_set('clean_url', $clean_url_original);
+    variable_set('clean_url', $this->originalCleanUrl);
     variable_set('site_mail', 'simpletest@example.com');
     variable_set('date_default_timezone', date_default_timezone_get());
     // Set up English language.
diff --git a/core/modules/simpletest/tests/upgrade/upgrade.test b/core/modules/simpletest/tests/upgrade/upgrade.test
index ac579fc..3e91b96 100644
--- a/core/modules/simpletest/tests/upgrade/upgrade.test
+++ b/core/modules/simpletest/tests/upgrade/upgrade.test
@@ -331,3 +331,240 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase {
   }
 
 }
+
+/**
+ * Perform end-to-end tests of the upgrade path.
+ */
+abstract class UpgradePathNGTestCase extends DrupalWebTestCase {
+  protected $profile = 'testing';
+
+  /**
+   * Installation profile of previous Drupal version to install.
+   *
+   * @todo Switch to Minimal.
+   */
+  protected $oldProfile = 'standard';
+
+  /**
+   * Original cURL options backup.
+   *
+   * Drupal doesn't allow to install Drupal with a user agent containing
+   * "simpletest", so we need to temporarily switch it to something else.
+   */
+  protected $originalAdditionalCurlOptions = array();
+
+  /**
+   * Replaces DrupalWebTestCase::setUp().
+   */
+  protected function setUp() {
+    global $user;
+
+    $this->upgrade_root = variable_get('file_public_path', conf_path() . '/files') . '/upgrade';
+    $this->upgrade_url = $GLOBALS['base_url'] . '/' . $this->upgrade_root;
+
+    // Delete the Drupal checkout.
+    // @todo 
+    #file_unmanaged_delete_recursive($this->upgrade_root);
+    // Recreate the Drupal checkout root directory.
+    file_prepare_directory($this->upgrade_root, FILE_CREATE_DIRECTORY);
+
+    // Setup verbose files directory etc.
+    // @todo Hm. We only need prepareEnvironment(), but without a databasePrefix
+    //   the test batch throws fatal errors, as it tries to access the original
+    //   db connection.
+    $this->prepareDatabasePrefix();
+    $this->prepareEnvironment();
+
+    $this->prepareCheckout();
+    $this->prepareUpgradeEnvironment();
+
+    // install.core.inc actively prevents a user agent containing "simpletest"
+    // to install Drupal.  DrupalWTF!
+    $this->originalAdditionalCurlOptions = $this->additionalCurlOptions;
+    $this->additionalCurlOptions[CURLOPT_USERAGENT] = 'Drupal';
+
+    // Install the previous version of Drupal.
+    $this->installDrupal();
+
+    // Revert everything we changed.
+    $this->additionalCurlOptions = $this->originalAdditionalCurlOptions;
+
+    // Lastly, change the database prefix to the one of the freshly installed
+    // child site, so we can perform the upgrade.
+    $this->changeDatabasePrefix();
+
+    // Log in with a clean $user.
+    $this->originalUser = $user;
+    drupal_save_session(FALSE);
+    $user = user_load(1);
+
+    $this->setup = TRUE;
+  }
+
+  protected function prepareCheckout() {
+    // @see http://php.net/manual/en/language.operators.execution.php
+    debug(`rm -rf {$this->upgrade_root}/`);
+    debug(`mkdir {$this->upgrade_root}`);
+    debug(`git clone --branch 7.x http://git.drupal.org/project/drupal.git {$this->upgrade_root}`);
+    // debug(`cp -R .git {$this->upgrade_root}`);
+    // debug(`git --git-dir={$this->upgrade_root}/.git --work-tree={$this->upgrade_root} checkout origin/7.x`);
+  }
+
+  protected function prepareUpgradeEnvironment() {
+    // Revert public filesystem security.
+    $htaccess_file = $this->upgrade_root . '/.htaccess';
+    $htaccess = file_get_contents($htaccess_file);
+    if (strpos($htaccess, 'SetHandler') === FALSE) {
+      $htaccess = 'SetHandler none
+Options All
+'. $htaccess;
+      file_put_contents($htaccess_file, $htaccess);
+    }
+
+    // Create the settings file.
+    $settings_file = $this->upgrade_root .'/sites/default/settings.php';
+    $settings = file_get_contents($this->upgrade_root .'/sites/default/default.settings.php');
+    $connection_info = Database::getConnectionInfo('default');
+    $connection_info['default']['prefix']['default'] = $connection_info['default']['prefix']['default'] . $this->databasePrefix;
+
+    $extra_settings = '$databases["default"] = '. var_export($connection_info, TRUE) .";\n";
+    $extra_settings .= '$conf["cache_backends"][] = "includes/cache-install.inc";' ."\n";
+    $extra_settings .= '$conf["cache_default_class"] = "DrupalFakeCache";';
+    $settings .= "\n$extra_settings\n";
+    file_put_contents($settings_file, $settings);
+    
+  }
+
+  protected function installDrupal() {
+    $this->drupalGet("$this->upgrade_url/install.php", array('external' => TRUE));
+
+    // Profile selection.
+    $edit = array(
+      'profile' => $this->oldProfile,
+    );
+    $this->drupalPost(NULL, $edit, t('Save and continue'));
+
+    // Language selection.
+    $this->drupalPost(NULL, array(), t('Save and continue'));
+
+    // Site setup.
+    $this->root_user = (object) array(
+      'uid' => 1,
+      'name' => 'admin',
+      'mail' => 'simpletest@example.com',
+      'pass_raw' => $this->randomName(),
+    );
+    $edit = array(
+      'site_mail' => 'simpletest@example.com',
+      'account[name]' => $this->root_user->name,
+      'account[mail]' => $this->root_user->mail,
+      'account[pass][pass1]' => $this->root_user->pass_raw,
+      'account[pass][pass2]' => $this->root_user->pass_raw,
+      //'site_default_country' => '',
+      //'date_default_timezone' => date_default_timezone_get(),
+      'update_status_module[1]' => FALSE,
+    );
+    $this->drupalPost(NULL, $edit, t('Save and continue'));
+
+    // Finally coming home.
+    $this->clickLink(t('Visit your new site'));
+
+  }
+
+  /**
+   * Perform the upgrade.
+   *
+   * @param $register_errors
+   *   Register the errors during the upgrade process as failures.
+   * @return
+   *   TRUE if the upgrade succeeded, FALSE otherwise.
+   */
+  protected function performUpgrade($register_errors = TRUE) {
+    $update_url = $GLOBALS['base_url'] . '/core/update.php';
+
+    // Load the first update screen.
+    $this->drupalGet($update_url, array('external' => TRUE));
+    if (!$this->assertResponse(200)) {
+      return FALSE;
+    }
+
+    // Continue.
+    $this->drupalPost(NULL, array(), t('Continue'));
+    if (!$this->assertResponse(200)) {
+      return FALSE;
+    }
+
+    // Go!
+    $this->drupalPost(NULL, array(), t('Apply pending updates'));
+    if (!$this->assertText('Updates were attempted')) {
+      return FALSE;
+    }
+
+    // Check for errors during the update process.
+    foreach ($this->xpath('//li[@class=:class]', array(':class' => 'failure')) as $element) {
+      $message = strip_tags($element->asXML());
+      $this->upgradeErrors[] = $message;
+      if ($register_errors) {
+        $this->fail($message);
+      }
+    }
+
+    if (!empty($this->upgradeErrors)) {
+      // Upgrade failed, the installation might be in an inconsistent state,
+      // don't process.
+      return FALSE;
+    }
+
+    // Check if there still are pending updates.
+    $this->drupalGet($update_url, array('external' => TRUE));
+    $this->drupalPost(NULL, array(), t('Continue'));
+    if (!$this->assertText(t('No pending updates.'), t('No pending updates at the end of the update process.'))) {
+      return FALSE;
+    }
+
+    // Upgrade succeed, rebuild the environment so that we can call the API
+    // of the child site directly from this request.
+    $this->upgradedSite = TRUE;
+
+    // Reload module list. For modules that are enabled in the test database,
+    // but not on the test client, we need to load the code here.
+//    $new_modules = array_diff(module_list(TRUE), $this->loadedModules);
+//    foreach ($new_modules as $module) {
+//      drupal_load('module', $module);
+//    }
+
+    // Reload hook implementations
+    module_implements_reset();
+
+    // Rebuild caches.
+    drupal_static_reset();
+    drupal_flush_all_caches();
+
+    // Reload global $conf array and permissions.
+    $this->refreshVariables();
+    $this->checkPermissions(array(), TRUE);
+
+    // Check we can load the front page of the new site.
+    $this->drupalGet('');
+    return $this->assertText('Powered by Drupal', t('The front page of the upgraded site loads successfully.'));
+  }
+
+  /**
+   * Force uninstall all modules from a test database, except those listed.
+   *
+   * @param $modules
+   *   The list of modules to keep installed. Required core modules will
+   *   always be kept.
+   */
+  protected function uninstallModulesExcept(array $modules) {
+    $required_modules = array('block', 'dblog', 'filter', 'node', 'system', 'update', 'user');
+
+    $modules = array_merge($required_modules, $modules);
+
+    db_delete('system')
+      ->condition('type', 'module')
+      ->condition('name', $modules, 'NOT IN')
+      ->execute();
+  }
+
+}
diff --git a/core/modules/simpletest/tests/upgrade/upgrade_bare.test b/core/modules/simpletest/tests/upgrade/upgrade_bare.test
index f507aea..e9e500d 100644
--- a/core/modules/simpletest/tests/upgrade/upgrade_bare.test
+++ b/core/modules/simpletest/tests/upgrade/upgrade_bare.test
@@ -5,7 +5,7 @@
  *
  * Load an empty installation of Drupal 7 and run the upgrade process on it.
  */
-class BareUpgradePathTestCase extends UpgradePathTestCase {
+class BareUpgradePathTestCase extends UpgradePathNGTestCase {
   public static function getInfo() {
     return array(
       'name'  => 'Bare upgrade test',
@@ -14,14 +14,6 @@ class BareUpgradePathTestCase extends UpgradePathTestCase {
     );
   }
 
-  public function setUp() {
-    // Path to the database dump.
-    $this->databaseDumpFiles = array(
-      drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-7.bare.database.php.gz',
-    );
-    parent::setUp();
-  }
-
   /**
    * Test a successful upgrade.
    */
diff --git a/core/update.php b/core/update.php
index e7e4e5c..d19fcc0 100644
--- a/core/update.php
+++ b/core/update.php
@@ -285,6 +285,10 @@ function update_access_allowed() {
   if (!empty($update_free_access)) {
     return TRUE;
   }
+  // Allow tests to access update.php.
+  if (drupal_valid_test_ua()) {
+    return TRUE;
+  }
   // Calls to user_access() might fail during the Drupal 6 to 7 update process,
   // so we fall back on requiring that the user be logged in as user #1.
   try {
