From 05f77ccc6ea3a42c60cf945c261c06d09c3f6c2d Mon Sep 17 00:00:00 2001
From: webchick <webchick@24967.no-reply.drupal.org>
Date: Tue, 30 Aug 2011 01:06:58 -0700
Subject: [PATCH] Issue #978944 by Aron Novak, chx, ksenzee: Fixed Handle
 exceptions thrown in cron.

---
 includes/common.inc                             | 10 +++++++++-
 modules/simpletest/tests/common_test.module     | 13 +++++++++++++
 .../tests/common_test_cron_helper.info          |  6 ++++++
 .../tests/common_test_cron_helper.module        | 17 +++++++++++++++++
 modules/system/system.test                      | 17 +++++++++++++++++
 5 files changed, 62 insertions(+), 1 deletion(-)
 create mode 100644 modules/simpletest/tests/common_test_cron_helper.info
 create mode 100644 modules/simpletest/tests/common_test_cron_helper.module

diff --git a/includes/common.inc b/includes/common.inc
index 1ef681f121a9..f54f29a7c39f 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -5041,7 +5041,15 @@ function drupal_cron_run() {
     drupal_register_shutdown_function('drupal_cron_cleanup');
 
     // Iterate through the modules calling their cron handlers (if any):
-    module_invoke_all('cron');
+    foreach (module_implements('cron') as $module) {
+      // Do not let an exception thrown by one module disturb another.
+      try {
+        module_invoke($module, 'cron');
+      }
+      catch (Exception $e) {
+        watchdog_exception('cron', $e);
+      }
+    }
 
     // Record cron time
     variable_set('cron_last', REQUEST_TIME);
diff --git a/modules/simpletest/tests/common_test.module b/modules/simpletest/tests/common_test.module
index 9b6178804c90..c400eaed1142 100644
--- a/modules/simpletest/tests/common_test.module
+++ b/modules/simpletest/tests/common_test.module
@@ -225,3 +225,16 @@ function common_test_js_and_css_querystring() {
    drupal_add_css('/' . drupal_get_path('module', 'node') . '/node-fake.css?arg1=value1&arg2=value2');
    return '';
 }
+
+/**
+ * Implements hook_cron().
+ *
+ * System module should handle if a module does not catch an exception and keep
+ * cron going.
+ *
+ * @see common_test_cron_helper()
+ *
+ */
+function common_test_cron() {
+  throw new Exception(t('Uncaught exception'));
+}
diff --git a/modules/simpletest/tests/common_test_cron_helper.info b/modules/simpletest/tests/common_test_cron_helper.info
new file mode 100644
index 000000000000..ce1a6326fb33
--- /dev/null
+++ b/modules/simpletest/tests/common_test_cron_helper.info
@@ -0,0 +1,6 @@
+name = "Common Test Cron Helper"
+description = "Helper module for CronRunTestCase::testCronExceptions()."
+package = Testing
+version = VERSION
+core = 7.x
+hidden = TRUE
diff --git a/modules/simpletest/tests/common_test_cron_helper.module b/modules/simpletest/tests/common_test_cron_helper.module
new file mode 100644
index 000000000000..94a2b2c43821
--- /dev/null
+++ b/modules/simpletest/tests/common_test_cron_helper.module
@@ -0,0 +1,17 @@
+<?php
+/**
+ * @file
+ * Helper module for the testCronExceptions in addition to common_test module.
+ */
+
+/**
+ * Implements hook_cron().
+ *
+ * common_test_cron() throws an exception, but the execution should reach this
+ * function as well.
+ *
+ * @see common_test_cron()
+ */
+function common_test_cron_helper_cron() {
+  variable_set('common_test_cron', 'success');
+}
diff --git a/modules/system/system.test b/modules/system/system.test
index 181ddeafd29e..1ce8e6b7e0ed 100644
--- a/modules/system/system.test
+++ b/modules/system/system.test
@@ -695,6 +695,10 @@ class CronRunTestCase extends DrupalWebTestCase {
     );
   }
 
+  function setUp() {
+    parent::setUp(array('common_test', 'common_test_cron_helper'));
+  }
+
   /**
    * Test cron runs.
    */
@@ -799,6 +803,19 @@ class CronRunTestCase extends DrupalWebTestCase {
     $this->assertTrue(file_exists($perm_old->uri), t('Old permanent file was correctly ignored.'));
     $this->assertTrue(file_exists($perm_new->uri), t('New permanent file was correctly ignored.'));
   }
+
+  /**
+   * Make sure exceptions thrown on hook_cron() don't affect other modules.
+   */
+  function testCronExceptions() {
+    variable_del('common_test_cron');
+    // The common_test module throws an exception. If it isn't caught, the tests
+    // won't finish successfully.
+    // The common_test_cron_helper module sets the 'common_test_cron' variable.
+    $this->cronRun();
+    $result = variable_get('common_test_cron');
+    $this->assertEqual($result, 'success', t('Cron correctly handles exceptions thrown during hook_cron() invocations.'));
+  }
 }
 
 class AdminMetaTagTestCase extends DrupalWebTestCase {
-- 
GitLab