diff --git a/core/modules/ckeditor/js/plugins/drupalimage/plugin.js b/core/modules/ckeditor/js/plugins/drupalimage/plugin.js
index c481264473cf43bd0d56c0d41de58c377800757a..80921c250793365ff07920cd7b2f5620f83bbf4f 100644
--- a/core/modules/ckeditor/js/plugins/drupalimage/plugin.js
+++ b/core/modules/ckeditor/js/plugins/drupalimage/plugin.js
@@ -65,11 +65,14 @@
         }
         widgetDefinition.allowedContent = new CKEDITOR.style(allowedContentDefinition);
 
+        // Override the 'link' part, to completely disable image2's link
+        // support: http://dev.ckeditor.com/ticket/11341.
+        widgetDefinition.parts.link = 'This is a nonsensical selector to disable this functionality completely';
+
         // Override downcast(): since we only accept <img> in our upcast method,
         // the element is already correct. We only need to update the element's
         // data-entity-uuid attribute.
         widgetDefinition.downcast = function (element) {
-          element.attributes['data-entity-type'] = this.data['data-entity-type'];
           element.attributes['data-entity-uuid'] = this.data['data-entity-uuid'];
         };
 
@@ -173,18 +176,6 @@
             return widget;
           };
         };
-
-        var originalInit = widgetDefinition.init;
-        widgetDefinition.init = function () {
-          originalInit.call(this);
-
-          // Update data.link object with attributes if the link has been
-          // discovered.
-          // @see plugins/image2/plugin.js/init() in CKEditor; this is similar.
-          if (this.parts.link) {
-            this.setData('link', CKEDITOR.plugins.link.parseLinkAttributes(editor, this.parts.link));
-          }
-        };
       });
 
       // Add a widget#edit listener to every instance of image2 widget in order
@@ -242,86 +233,25 @@
       }
     },
 
+    // Disable image2's integration with the link/drupallink plugins: don't
+    // allow the widget itself to become a link. Support for that may be added
+    // by an text filter that adds a data- attribute specifically for that.
     afterInit: function (editor) {
-      linkCommandIntegrator(editor);
-    }
-
-  });
-
-  /**
-   * Integrates the drupalimage widget with the drupallink plugin.
-   *
-   * Makes images linkable.
-   *
-   * @param {CKEDITOR.editor} editor
-   *   A CKEditor instance.
-   */
-  function linkCommandIntegrator(editor) {
-    // Nothing to integrate with if the drupallink plugin is not loaded.
-    if (!editor.plugins.drupallink) {
-      return;
-    }
-
-    // Override default behaviour of 'drupalunlink' command.
-    editor.getCommand('drupalunlink').on('exec', function (evt) {
-      var widget = getFocusedWidget(editor);
-
-      // Override 'drupalunlink' only when link truly belongs to the widget. If
-      // wrapped inline widget in a link, let default unlink work.
-      // @see https://dev.ckeditor.com/ticket/11814
-      if (!widget || !widget.parts.link) {
-        return;
-      }
-
-      widget.setData('link', null);
-
-      // Selection (which is fake) may not change if unlinked image in focused
-      // widget, i.e. if captioned image. Let's refresh command state manually
-      // here.
-      this.refresh(editor, editor.elementPath());
-
-      evt.cancel();
-    });
-
-    // Override default refresh of 'drupalunlink' command.
-    editor.getCommand('drupalunlink').on('refresh', function (evt) {
-      var widget = getFocusedWidget(editor);
-
-      if (!widget) {
-        return;
+      if (editor.plugins.drupallink) {
+        var cmd = editor.getCommand('drupallink');
+        // Needs to be refreshed on selection changes.
+        cmd.contextSensitive = 1;
+        // Disable command and cancel event when the image widget is selected.
+        cmd.on('refresh', function (evt) {
+          var widget = editor.widgets.focused;
+          if (widget && widget.name === 'image') {
+            this.setState(CKEDITOR.TRISTATE_DISABLED);
+            evt.cancel();
+          }
+        });
       }
-
-      // Note that widget may be wrapped in a link, which
-      // does not belong to that widget (#11814).
-      this.setState(widget.data.link || widget.wrapper.getAscendant('a') ?
-        CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED);
-
-      evt.cancel();
-    });
-  }
-
-  /**
-   * Gets the focused widget, if of the type specific for this plugin.
-   *
-   * @param {CKEDITOR.editor} editor
-   *   A CKEditor instance.
-   *
-   * @return {?CKEDITOR.plugins.widget}
-   *   The focused image2 widget instance, or null.
-   */
-  function getFocusedWidget(editor) {
-    var widget = editor.widgets.focused;
-
-    if (widget && widget.name === 'image') {
-      return widget;
     }
 
-    return null;
-  }
-
-  // Expose an API for other plugins to interact with drupalimage widgets.
-  CKEDITOR.plugins.drupalimage = {
-    getFocusedWidget: getFocusedWidget
-  };
+  });
 
 })(jQuery, Drupal, CKEDITOR);
diff --git a/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js b/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js
index 9fba103c308bc4b22f2c30f3443679541298746e..8dd91b17048c462a2147b8a6d82e81b59b76094f 100644
--- a/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js
+++ b/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js
@@ -71,9 +71,10 @@
         // data-caption attributes.
         var originalDowncast = widgetDefinition.downcast;
         widgetDefinition.downcast = function (element) {
-          var img = findElementByName(element, 'img');
-          originalDowncast.call(this, img);
-
+          var img = originalDowncast.call(this, element);
+          if (!img) {
+            img = findElementByName(element, 'img');
+          }
           var caption = this.editables.caption;
           var captionHtml = caption && caption.getData();
           var attrs = img.attributes;
@@ -90,14 +91,10 @@
               attrs['data-align'] = this.data.align;
             }
           }
+          attrs['data-entity-type'] = this.data['data-entity-type'];
+          attrs['data-entity-uuid'] = this.data['data-entity-uuid'];
 
-          // If img is wrapped with a link, we want to return that link.
-          if (img.parent.name === 'a') {
-            return img.parent;
-          }
-          else {
-            return img;
-          }
+          return img;
         };
 
         // We want to upcast <img> elements to a DOM structure required by the
@@ -118,11 +115,6 @@
 
           element = originalUpcast.call(this, element, data);
           var attrs = element.attributes;
-
-          if (element.parent.name === 'a') {
-            element = element.parent;
-          }
-
           var retElement = element;
           var caption;
 
diff --git a/core/modules/ckeditor/js/plugins/drupallink/plugin.js b/core/modules/ckeditor/js/plugins/drupallink/plugin.js
index 2cc9bc10069f5409be8ee9d7804434ea9c35d3fa..e9fb555b8eda2bff4100568b7989a55a75f02822 100644
--- a/core/modules/ckeditor/js/plugins/drupallink/plugin.js
+++ b/core/modules/ckeditor/js/plugins/drupallink/plugin.js
@@ -31,8 +31,6 @@
         modes: {wysiwyg: 1},
         canUndo: true,
         exec: function (editor) {
-          var drupalImageUtils = CKEDITOR.plugins.drupalimage;
-          var focusedImageWidget = drupalImageUtils && drupalImageUtils.getFocusedWidget(editor);
           var linkElement = getSelectedLink(editor);
           var linkDOMElement = null;
 
@@ -58,30 +56,9 @@
               existingValues[attributeName] = linkElement.data('cke-saved-' + attributeName) || attribute.nodeValue;
             }
           }
-          // Or, if an image widget is focused, we're editing a link wrapping
-          // an image widget.
-          else if (focusedImageWidget && focusedImageWidget.data.link) {
-            var url = focusedImageWidget.data.link.url;
-            existingValues.href = url.protocol + url.url;
-          }
 
           // Prepare a save callback to be used upon saving the dialog.
           var saveCallback = function (returnValues) {
-            // If an image widget is focused, we're not editing an independent
-            // link, but we're wrapping an image widget in a link.
-            if (focusedImageWidget) {
-              var urlMatch = returnValues.attributes.href.match(urlRegex);
-              focusedImageWidget.setData('link', {
-                type: 'url',
-                url: {
-                  protocol: urlMatch[1],
-                  url: urlMatch[2]
-                }
-              });
-              editor.fire('saveSnapshot');
-              return;
-            }
-
             editor.fire('saveSnapshot');
 
             // Create a new link element if needed.
@@ -279,57 +256,4 @@
     return null;
   }
 
-  var urlRegex = /^((?:http|https):\/\/)?(.*)$/;
-
-  /**
-   * The image2 plugin is currently tightly coupled to the link plugin: it
-   * calls CKEDITOR.plugins.link.parseLinkAttributes().
-   *
-   * Drupal 8's CKEditor build doesn't include the 'link' plugin. Because it
-   * includes its own link plugin that integrates with Drupal's dialog system.
-   * So, to allow images to be linked, we need to duplicate the necessary subset
-   * of the logic.
-   *
-   * @todo Remove once we update to CKEditor 4.5.5.
-   * @see https://dev.ckeditor.com/ticket/13885
-   */
-  CKEDITOR.plugins.link = CKEDITOR.plugins.link || {
-    parseLinkAttributes: function (editor, element) {
-      var href = (element && (element.data('cke-saved-href') || element.getAttribute('href'))) || '';
-      var urlMatch = href.match(urlRegex);
-      return {
-        type: 'url',
-        url: {
-          protocol: urlMatch[1],
-          url: urlMatch[2]
-        }
-      };
-    },
-    getLinkAttributes: function (editor, data) {
-      var set = {};
-
-      var protocol = (data.url && typeof data.url.protocol !== 'undefined') ? data.url.protocol : 'http://';
-      var url = (data.url && CKEDITOR.tools.trim(data.url.url)) || '';
-      set['data-cke-saved-href'] = (url.indexOf('/') === 0) ? url : protocol + url;
-
-      // Browser need the "href" fro copy/paste link to work. (#6641)
-      if (set['data-cke-saved-href']) {
-        set.href = set['data-cke-saved-href'];
-      }
-
-      // Remove all attributes which are not currently set.
-      var removed = {};
-      for (var s in set) {
-        if (set.hasOwnProperty(s)) {
-          delete removed[s];
-        }
-      }
-
-      return {
-        set: set,
-        removed: CKEDITOR.tools.objectKeys(removed)
-      };
-    }
-  };
-
 })(jQuery, Drupal, drupalSettings, CKEDITOR);
diff --git a/core/modules/filter/src/Plugin/Filter/FilterCaption.php b/core/modules/filter/src/Plugin/Filter/FilterCaption.php
index 76a11258303e28f35eeb12d8bd96a54ecdddd090..37c18cc3bc76d66fc9a7d9838f556b16ca3325b4 100644
--- a/core/modules/filter/src/Plugin/Filter/FilterCaption.php
+++ b/core/modules/filter/src/Plugin/Filter/FilterCaption.php
@@ -55,17 +55,15 @@ public function process($text, $langcode) {
         // Given the updated node and caption: re-render it with a caption, but
         // bubble up the value of the class attribute of the captioned element,
         // this allows it to collaborate with e.g. the filter_align filter.
-        $tag = $node->tagName;
         $classes = $node->getAttribute('class');
         $node->removeAttribute('class');
-        $node = ($node->parentNode->tagName === 'a') ? $node->parentNode : $node;
         $filter_caption = array(
           '#theme' => 'filter_caption',
           // We pass the unsanitized string because this is a text format
           // filter, and after filtering, we always assume the output is safe.
           // @see \Drupal\filter\Element\ProcessedText::preRenderText()
           '#node' => FilteredMarkup::create($node->C14N()),
-          '#tag' => $tag,
+          '#tag' => $node->tagName,
           '#caption' => $caption,
           '#classes' => $classes,
         );
@@ -80,7 +78,7 @@ public function process($text, $langcode) {
         // Import the updated node from the new DOMDocument into the original
         // one, importing also the child nodes of the updated node.
         $updated_node = $dom->importNode($updated_node, TRUE);
-        // Finally, replace the original node with the new node.
+        // Finally, replace the original image node with the new image node!
         $node->parentNode->replaceChild($updated_node, $node);
       }
 
diff --git a/core/modules/filter/src/Tests/FilterUnitTest.php b/core/modules/filter/src/Tests/FilterUnitTest.php
index 801db4e2fc0bd47dd6459a2a49f934c40f907b22..54a738dd027f1781d855fb76fe5fff295a8bebb7 100644
--- a/core/modules/filter/src/Tests/FilterUnitTest.php
+++ b/core/modules/filter/src/Tests/FilterUnitTest.php
@@ -184,13 +184,6 @@ function testCaptionFilter() {
     $this->assertIdentical($expected, $output->getProcessedText());
     $this->assertIdentical($attached_library, $output->getAttachments());
 
-    // Ensure the caption filter works for linked images.
-    $input = '<a href="http://example.com/llamas/are/awesome/but/kittens/are/cool/too"><img src="llama.jpg" data-caption="Loquacious llama!" /></a>';
-    $expected = '<figure role="group"><a href="http://example.com/llamas/are/awesome/but/kittens/are/cool/too"><img src="llama.jpg" /></a>' . "\n" . '<figcaption>Loquacious llama!</figcaption></figure>';
-    $output = $test($input);
-    $this->assertIdentical($expected, $output->getProcessedText());
-    $this->assertIdentical($attached_library, $output->getAttachments());
-
     // So far we've tested that the caption filter works correctly. But we also
     // want to make sure that it works well in tandem with the "Limit allowed
     // HTML tags" filter, which it is typically used with.
@@ -308,13 +301,6 @@ function testAlignAndCaptionFilters() {
     $output = $test($input);
     $this->assertIdentical($expected, $output->getProcessedText());
     $this->assertIdentical($attached_library, $output->getAttachments());
-
-    // Ensure both filters together work for linked images.
-    $input = '<a href="http://example.com/llamas/are/awesome/but/kittens/are/cool/too"><img src="llama.jpg" data-caption="Loquacious llama!" data-align="center" /></a>';
-    $expected = '<figure role="group" class="align-center"><a href="http://example.com/llamas/are/awesome/but/kittens/are/cool/too"><img src="llama.jpg" /></a>' . "\n" . '<figcaption>Loquacious llama!</figcaption></figure>';
-    $output = $test($input);
-    $this->assertIdentical($expected, $output->getProcessedText());
-    $this->assertIdentical($attached_library, $output->getAttachments());
   }
 
   /**
diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index 74d348e9234dd72f6ff82ee17dcdc74370ec8bd4..b99435222f1e92bce3caa900525a6e5346364d4b 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -170,20 +170,17 @@ function simpletest_run_tests($test_list) {
  * @param $unescaped_test_classnames
  *   An array of test class names, including full namespaces, to be passed as
  *   a regular expression to PHPUnit's --filter option.
- * @param int $status
- *   (optional) The exit status code of the PHPUnit process will be assigned to
- *   this variable.
  *
  * @return array
  *   The parsed results of PHPUnit's JUnit XML output, in the format of
  *   {simpletest}'s schema.
  */
-function simpletest_run_phpunit_tests($test_id, array $unescaped_test_classnames, &$status = NULL) {
+function simpletest_run_phpunit_tests($test_id, array $unescaped_test_classnames) {
   $phpunit_file = simpletest_phpunit_xml_filepath($test_id);
-  simpletest_phpunit_run_command($unescaped_test_classnames, $phpunit_file, $status);
-  // A $status of 0 = passed test, 1 = failed test, > 1 indicates segfault
+  $ret = simpletest_phpunit_run_command($unescaped_test_classnames, $phpunit_file);
+  // A return value of 0 = passed test, 1 = failed test, > 1 indicates segfault
   // timeout, or other type of failure.
-  if ($status > 1) {
+  if ($ret > 1) {
     // Something broke during the execution of phpunit.
     // Return an error record of all failed classes.
     $rows[] = [
@@ -254,14 +251,11 @@ function simpletest_phpunit_configuration_filepath() {
  *   a regular expression to PHPUnit's --filter option.
  * @param string $phpunit_file
  *   A filepath to use for PHPUnit's --log-junit option.
- * @param int $status
- *   (optional) The exit status code of the PHPUnit process will be assigned to
- *   this variable.
  *
  * @return string
  *  The results as returned by exec().
  */
-function simpletest_phpunit_run_command(array $unescaped_test_classnames, $phpunit_file, &$status = NULL) {
+function simpletest_phpunit_run_command(array $unescaped_test_classnames, $phpunit_file) {
   // Setup an environment variable containing the database connection so that
   // functional tests can connect to the database.
   putenv('SIMPLETEST_DB=' . Database::getConnectionInfoAsUrl());
@@ -298,8 +292,7 @@ function simpletest_phpunit_run_command(array $unescaped_test_classnames, $phpun
 
   // exec in a subshell so that the environment is isolated when running tests
   // via the simpletest UI.
-  $ret = exec(join($command, " "), $output, $status);
-
+  exec(join($command, " "), $output, $ret);
   chdir($old_cwd);
   putenv('SIMPLETEST_DB=');
   return $ret;
diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index 0ad9a5c8ec652169b41087841aed25ef7ee0432f..9ca309f487f8111da24ac8e334f2296c5b92faf4 100755
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -23,68 +23,46 @@
 // Restricting the chunk of queries prevents memory exhaustion.
 const SIMPLETEST_SCRIPT_SQLITE_VARIABLE_LIMIT = 350;
 
-const SIMPLETEST_SCRIPT_EXIT_SUCCESS = 0;
-const SIMPLETEST_SCRIPT_EXIT_FAILURE = 1;
-const SIMPLETEST_SCRIPT_EXIT_EXCEPTION = 2;
-
 // Set defaults and get overrides.
 list($args, $count) = simpletest_script_parse_args();
 
 if ($args['help'] || $count == 0) {
   simpletest_script_help();
-  exit(($count == 0) ? SIMPLETEST_SCRIPT_EXIT_FAILURE : SIMPLETEST_SCRIPT_EXIT_SUCCESS);
+  exit;
 }
 
 simpletest_script_init();
 
-try {
-  $request = Request::createFromGlobals();
-  $kernel = TestRunnerKernel::createFromRequest($request, $autoloader);
-  $kernel->prepareLegacyRequest($request);
-}
-catch (Exception $e) {
-  echo (string) $e;
-  exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
-}
+$request = Request::createFromGlobals();
+$kernel = TestRunnerKernel::createFromRequest($request, $autoloader);
+$kernel->prepareLegacyRequest($request);
 
 if ($args['execute-test']) {
   simpletest_script_setup_database();
   simpletest_script_run_one_test($args['test-id'], $args['execute-test']);
   // Sub-process exited already; this is just for clarity.
-  exit(SIMPLETEST_SCRIPT_EXIT_SUCCESS);
+  exit;
 }
 
 if ($args['list']) {
   // Display all available tests.
   echo "\nAvailable test groups & classes\n";
   echo   "-------------------------------\n\n";
-  try {
-    $groups = simpletest_test_get_all($args['module']);
-  }
-  catch (Exception $e) {
-    echo (string) $e;
-    exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
-  }
+  $groups = simpletest_test_get_all($args['module']);
   foreach ($groups as $group => $tests) {
     echo $group . "\n";
     foreach ($tests as $class => $info) {
       echo " - $class\n";
     }
   }
-  exit(SIMPLETEST_SCRIPT_EXIT_SUCCESS);
+  exit;
 }
 
 simpletest_script_setup_database(TRUE);
 
 if ($args['clean']) {
   // Clean up left-over tables and directories.
-  try {
-    simpletest_clean_environment();
-  }
-  catch (Exception $e) {
-    echo (string) $e;
-    exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
-  }
+  simpletest_clean_environment();
   echo "\nEnvironment cleaned.\n";
 
   // Get the status messages and print them.
@@ -92,7 +70,7 @@
   foreach ($messages['status'] as $text) {
     echo " - " . $text . "\n";
   }
-  exit(SIMPLETEST_SCRIPT_EXIT_SUCCESS);
+  exit;
 }
 
 $test_list = simpletest_script_get_test_list();
@@ -107,7 +85,7 @@
 }
 
 // Execute tests.
-$status = simpletest_script_execute_batch($tests_to_run);
+simpletest_script_execute_batch($tests_to_run);
 
 // Stop the timer.
 simpletest_script_reporter_timer_stop();
@@ -126,17 +104,11 @@
 
 // Clean up all test results.
 if (!$args['keep-results']) {
-  try {
-    simpletest_clean_results_table();
-  }
-  catch (Exception $e) {
-    echo (string) $e;
-    exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
-  }
+  simpletest_clean_results_table();
 }
 
 // Test complete, exit.
-exit($status);
+exit;
 
 /**
  * Print help text.
@@ -323,7 +295,7 @@ function simpletest_script_parse_args() {
       else {
         // Argument not found in list.
         simpletest_script_print_error("Unknown argument '$arg'.");
-        exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
+        exit;
       }
     }
     else {
@@ -336,7 +308,7 @@ function simpletest_script_parse_args() {
   // Validate the concurrency argument
   if (!is_numeric($args['concurrency']) || $args['concurrency'] <= 0) {
     simpletest_script_print_error("--concurrency must be a strictly positive integer.");
-    exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
+    exit;
   }
 
   if ($args['browser']) {
@@ -371,7 +343,7 @@ function simpletest_script_init() {
   else {
     simpletest_script_print_error('Unable to automatically determine the path to the PHP interpreter. Supply the --php command line argument.');
     simpletest_script_help();
-    exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
+    exit();
   }
 
   // Get URL from arguments.
@@ -469,7 +441,7 @@ function simpletest_script_setup_database($new = FALSE) {
     }
     catch (\InvalidArgumentException $e) {
       simpletest_script_print_error('Invalid --dburl. Reason: ' . $e->getMessage());
-      exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
+      exit(1);
     }
   }
   // Otherwise, use the default database connection from settings.php.
@@ -480,7 +452,7 @@ function simpletest_script_setup_database($new = FALSE) {
   // If there is no default database connection for tests, we cannot continue.
   if (!isset($databases['default']['default'])) {
     simpletest_script_print_error('Missing default database connection for tests. Use --dburl to specify one.');
-    exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
+    exit(1);
   }
   Database::addConnectionInfo('default', 'default', $databases['default']['default']);
 
@@ -524,33 +496,21 @@ function simpletest_script_setup_database($new = FALSE) {
   }
   catch (\PDOException $e) {
     simpletest_script_print_error($databases['test-runner']['default']['driver'] . ': ' . $e->getMessage());
-    exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
+    exit(1);
   }
   if ($new && $sqlite) {
     require_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'simpletest') . '/simpletest.install';
     foreach (simpletest_schema() as $name => $table_spec) {
-      try {
-        if ($schema->tableExists($name)) {
-          $schema->dropTable($name);
-        }
-        $schema->createTable($name, $table_spec);
-      }
-      catch (Exception $e) {
-        echo (string) $e;
-        exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
+      if ($schema->tableExists($name)) {
+        $schema->dropTable($name);
       }
+      $schema->createTable($name, $table_spec);
     }
   }
   // Verify that the Simpletest database schema exists by checking one table.
-  try {
-    if (!$schema->tableExists('simpletest')) {
-      simpletest_script_print_error('Missing Simpletest database schema. Either install Simpletest module or use the --sqlite parameter.');
-      exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
-    }
-  }
-  catch (Exception $e) {
-    echo (string) $e;
-    exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
+  if (!$schema->tableExists('simpletest')) {
+    simpletest_script_print_error('Missing Simpletest database schema. Either install Simpletest module or use the --sqlite parameter.');
+    exit(1);
   }
 }
 
@@ -560,8 +520,6 @@ function simpletest_script_setup_database($new = FALSE) {
 function simpletest_script_execute_batch($test_classes) {
   global $args, $test_ids;
 
-  $total_status = SIMPLETEST_SCRIPT_EXIT_SUCCESS;
-
   // Multi-process execution.
   $children = array();
   while (!empty($test_classes) || !empty($children)) {
@@ -570,16 +528,8 @@ function simpletest_script_execute_batch($test_classes) {
         break;
       }
 
-      try {
-        $test_id = Database::getConnection('default', 'test-runner')
-          ->insert('simpletest_test_id')
-          ->useDefaults(array('test_id'))
-          ->execute();
-      }
-      catch (Exception $e) {
-        echo (string) $e;
-        exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
-      }
+      $test_id = Database::getConnection('default', 'test-runner')
+        ->insert('simpletest_test_id')->useDefaults(array('test_id'))->execute();
       $test_ids[] = $test_id;
 
       $test_class = array_shift($test_classes);
@@ -589,7 +539,7 @@ function simpletest_script_execute_batch($test_classes) {
 
       if (!is_resource($process)) {
         echo "Unable to fork test process. Aborting.\n";
-        exit(SIMPLETEST_SCRIPT_EXIT_SUCCESS);
+        exit;
       }
 
       // Register our new child.
@@ -610,11 +560,7 @@ function simpletest_script_execute_batch($test_classes) {
       if (empty($status['running'])) {
         // The child exited, unregister it.
         proc_close($child['process']);
-        if ($status['exitcode'] === SIMPLETEST_SCRIPT_EXIT_FAILURE) {
-          $total_status = max($status['exitcode'], $total_status);
-        }
-        elseif ($status['exitcode']) {
-          $total_status = $status['exitcode'];
+        if ($status['exitcode']) {
           echo 'FATAL ' . $child['class'] . ': test runner returned a non-zero error code (' . $status['exitcode'] . ').' . "\n";
           if ($args['die-on-fail']) {
             list($db_prefix, ) = simpletest_last_test_get($child['test_id']);
@@ -635,19 +581,19 @@ function simpletest_script_execute_batch($test_classes) {
       }
     }
   }
-  return $total_status;
 }
 
 /**
  * Run a group of phpunit tests.
  */
 function simpletest_script_run_phpunit($test_id, $class) {
+
   $reflection = new \ReflectionClass($class);
   if ($reflection->hasProperty('runLimit')) {
     set_time_limit($reflection->getStaticPropertyValue('runLimit'));
   }
 
-  $results = simpletest_run_phpunit_tests($test_id, array($class), $status);
+  $results = simpletest_run_phpunit_tests($test_id, array($class));
   simpletest_process_phpunit_results($results);
 
   // Map phpunit results to a data structure we can pass to
@@ -682,7 +628,6 @@ function simpletest_script_run_phpunit($test_id, $class) {
   foreach ($summaries as $class => $summary) {
     simpletest_script_reporter_display_summary($class, $summary);
   }
-  return $status;
 }
 
 /**
@@ -703,28 +648,23 @@ function simpletest_script_run_one_test($test_id, $test_class) {
     }
     $test = new $class_name($test_id);
     if (is_subclass_of($test_class, '\PHPUnit_Framework_TestCase')) {
-      $status = simpletest_script_run_phpunit($test_id, $test_class);
+      simpletest_script_run_phpunit($test_id, $test_class);
     }
     else {
       $test->dieOnFail = (bool) $args['die-on-fail'];
       $test->verbose = (bool) $args['verbose'];
       $test->run($methods);
       simpletest_script_reporter_display_summary($test_class, $test->results);
-
-      $status = SIMPLETEST_SCRIPT_EXIT_SUCCESS;
-      // Finished, kill this runner.
-      if ($test->results['#fail'] || $test->results['#exception']) {
-        $status = SIMPLETEST_SCRIPT_EXIT_FAILURE;
-      }
     }
 
-    exit($status);
+    // Finished, kill this runner.
+    exit(0);
   }
   // DrupalTestCase::run() catches exceptions already, so this is only reached
   // when an exception is thrown in the wrapping test runner environment.
   catch (Exception $e) {
     echo (string) $e;
-    exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
+    exit(1);
   }
 }
 
@@ -786,13 +726,7 @@ function simpletest_script_cleanup($test_id, $test_class, $exitcode) {
     return;
   }
   // Retrieve the last database prefix used for testing.
-  try {
-    list($db_prefix,) = simpletest_last_test_get($test_id);
-  }
-  catch (Exception $e) {
-    echo (string) $e;
-    exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
-  }
+  list($db_prefix, ) = simpletest_last_test_get($test_id);
 
   // If no database prefix was found, then the test was not set up correctly.
   if (empty($db_prefix)) {
@@ -807,13 +741,7 @@ function simpletest_script_cleanup($test_id, $test_class, $exitcode) {
   $messages[] = "- Found database prefix '$db_prefix' for test ID $test_id.";
 
   // Read the log file in case any fatal errors caused the test to crash.
-  try {
-    simpletest_log_read($test_id, $db_prefix, $test_class);
-  }
-  catch (Exception $e) {
-    echo (string) $e;
-    exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
-  }
+  simpletest_log_read($test_id, $db_prefix, $test_class);
 
   // Check whether a test site directory was setup already.
   // @see \Drupal\simpletest\TestBase::prepareEnvironment()
@@ -835,19 +763,12 @@ function simpletest_script_cleanup($test_id, $test_class, $exitcode) {
   }
 
   // Clear out all database tables from the test.
-  try {
-    $schema = Database::getConnection('default', 'default')->schema();
-    $count = 0;
-    foreach ($schema->findTables($db_prefix . '%') as $table) {
-      $schema->dropTable($table);
-      $count++;
-    }
-  }
-  catch (Exception $e) {
-    echo (string) $e;
-    exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
+  $schema = Database::getConnection('default', 'default')->schema();
+  $count = 0;
+  foreach ($schema->findTables($db_prefix . '%') as $table) {
+    $schema->dropTable($table);
+    $count++;
   }
-
   if ($count) {
     $messages[] = "- Removed $count leftover tables.";
   }
@@ -871,13 +792,7 @@ function simpletest_script_get_test_list() {
 
   $test_list = array();
   if ($args['all'] || $args['module']) {
-    try {
-      $groups = simpletest_test_get_all($args['module']);
-    }
-    catch (Exception $e) {
-      echo (string) $e;
-      exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
-    }
+    $groups = simpletest_test_get_all($args['module']);
     $all_tests = array();
     foreach ($groups as $group => $tests) {
       $all_tests = array_merge($all_tests, array_keys($tests));
@@ -893,20 +808,14 @@ function simpletest_script_get_test_list() {
           $test_list[] = $test_class;
         }
         else {
-          try {
-            $groups = simpletest_test_get_all();
-          }
-          catch (Exception $e) {
-            echo (string) $e;
-            exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
-          }
+          $groups = simpletest_test_get_all();
           $all_classes = array();
           foreach ($groups as $group) {
             $all_classes = array_merge($all_classes, array_keys($group));
           }
           simpletest_script_print_error('Test class not found: ' . $class_name);
           simpletest_script_print_alternatives($class_name, $all_classes, 6);
-          exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
+          exit(1);
         }
       }
     }
@@ -915,7 +824,7 @@ function simpletest_script_get_test_list() {
       foreach ($args['test_names'] as $file) {
         if (!file_exists($file)) {
           simpletest_script_print_error('File not found: ' . $file);
-          exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
+          exit;
         }
         $content = file_get_contents($file);
         // Extract a potential namespace.
@@ -994,13 +903,7 @@ function simpletest_script_get_test_list() {
       }
     }
     else {
-      try {
-        $groups = simpletest_test_get_all();
-      }
-      catch (Exception $e) {
-        echo (string) $e;
-        exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
-      }
+      $groups = simpletest_test_get_all();
       foreach ($args['test_names'] as $group_name) {
         if (isset($groups[$group_name])) {
           $test_list = array_merge($test_list, array_keys($groups[$group_name]));
@@ -1008,7 +911,7 @@ function simpletest_script_get_test_list() {
         else {
           simpletest_script_print_error('Test group not found: ' . $group_name);
           simpletest_script_print_alternatives($group_name, array_keys($groups));
-          exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
+          exit(1);
         }
       }
     }
@@ -1016,7 +919,7 @@ function simpletest_script_get_test_list() {
 
   if (empty($test_list)) {
     simpletest_script_print_error('No valid tests were specified.');
-    exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
+    exit;
   }
   return $test_list;
 }
@@ -1090,13 +993,7 @@ function simpletest_script_reporter_display_summary($class, $results) {
 function simpletest_script_reporter_write_xml_results() {
   global $args, $test_ids, $results_map;
 
-  try {
-    $results = simpletest_script_load_messages_by_test_id($test_ids);
-  }
-  catch (Exception $e) {
-    echo (string) $e;
-    exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
-  }
+  $results = simpletest_script_load_messages_by_test_id($test_ids);
 
   $test_class = '';
   $xml_files = array();
@@ -1186,13 +1083,7 @@ function simpletest_script_reporter_display_results() {
     echo "Detailed test results\n";
     echo "---------------------\n";
 
-    try {
-      $results = simpletest_script_load_messages_by_test_id($test_ids);
-    }
-    catch (Exception $e) {
-      echo (string) $e;
-      exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
-    }
+    $results = simpletest_script_load_messages_by_test_id($test_ids);
     $test_class = '';
     foreach ($results as $result) {
       if (isset($results_map[$result->status])) {
@@ -1340,16 +1231,10 @@ function simpletest_script_load_messages_by_test_id($test_ids) {
   }
 
   foreach ($test_id_chunks as $test_id_chunk) {
-    try {
-      $result_chunk = Database::getConnection('default', 'test-runner')
-        ->query("SELECT * FROM {simpletest} WHERE test_id IN ( :test_ids[] ) ORDER BY test_class, message_id", array(
-          ':test_ids[]' => $test_id_chunk,
-        ))->fetchAll();
-    }
-    catch (Exception $e) {
-      echo (string) $e;
-      exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
-    }
+    $result_chunk = Database::getConnection('default', 'test-runner')
+      ->query("SELECT * FROM {simpletest} WHERE test_id IN ( :test_ids[] ) ORDER BY test_class, message_id", array(
+        ':test_ids[]' => $test_id_chunk,
+      ))->fetchAll();
     if ($result_chunk) {
       $results = array_merge($results, $result_chunk);
     }
@@ -1364,20 +1249,14 @@ function simpletest_script_load_messages_by_test_id($test_ids) {
 function simpletest_script_open_browser() {
   global $test_ids;
 
-  try {
-    $connection = Database::getConnection('default', 'test-runner');
-    $results = $connection->select('simpletest')
-      ->fields('simpletest')
-      ->condition('test_id', $test_ids, 'IN')
-      ->orderBy('test_class')
-      ->orderBy('message_id')
-      ->execute()
-      ->fetchAll();
-  }
-  catch (Exception $e) {
-    echo (string) $e;
-    exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
-  }
+  $connection = Database::getConnection('default', 'test-runner');
+  $results = $connection->select('simpletest')
+    ->fields('simpletest')
+    ->condition('test_id', $test_ids, 'IN')
+    ->orderBy('test_class')
+    ->orderBy('message_id')
+    ->execute()
+    ->fetchAll();
 
   // Get the results form.
   $form = array();