Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.249
diff -u -p -r1.249 bootstrap.inc
--- includes/bootstrap.inc	16 Nov 2008 19:41:14 -0000	1.249
+++ includes/bootstrap.inc	22 Nov 2008 10:12:45 -0000
@@ -1140,13 +1140,13 @@ function _drupal_bootstrap($phase) {
       break;
 
     case DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE:
-      // Load module handling.
-      require_once DRUPAL_ROOT . '/includes/module.inc';
       $cache_mode = variable_get('cache', CACHE_DISABLED);
       // Get the page from the cache.
       $cache = $cache_mode == CACHE_DISABLED ? '' : page_get_cache();
       // If the skipping of the bootstrap hooks is not enforced, call hook_boot.
-      if ($cache_mode != CACHE_AGGRESSIVE) {
+      if (!$cache || $cache_mode != CACHE_AGGRESSIVE) {
+        // Load module handling.
+        require_once DRUPAL_ROOT . '/includes/module.inc';
         bootstrap_invoke_all('boot');
       }
       // If there is a cached page, display it.
Index: modules/simpletest/tests/bootstrap.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/bootstrap.test,v
retrieving revision 1.4
diff -u -p -r1.4 bootstrap.test
--- modules/simpletest/tests/bootstrap.test	2 Nov 2008 10:56:35 -0000	1.4
+++ modules/simpletest/tests/bootstrap.test	22 Nov 2008 10:15:37 -0000
@@ -3,9 +3,6 @@
 
 class BootstrapIPAddressTestCase extends DrupalWebTestCase {
 
-  /**
-   * Implementation of getInfo().
-   */
   function getInfo() {
     return array(
       'name' => t('IP address and HTTP_HOST test'),
@@ -14,9 +11,6 @@ class BootstrapIPAddressTestCase extends
     );
   }
 
-  /**
-   * Implementation of setUp().
-   */
   function setUp() {
     $this->oldserver = $_SERVER;
 
@@ -33,9 +27,6 @@ class BootstrapIPAddressTestCase extends
     parent::setUp();
   }
 
-  /**
-   * Implementation of tearDown().
-   */
   function tearDown() {
     $_SERVER = $this->oldserver;
     parent::tearDown();
@@ -95,9 +86,6 @@ class BootstrapIPAddressTestCase extends
 
 class BootstrapPageCacheTestCase extends DrupalWebTestCase {
 
-  /**
-   * Implementation of getInfo().
-   */
   function getInfo() {
     return array(
       'name' => t('Page cache test'),
@@ -121,16 +109,10 @@ class BootstrapPageCacheTestCase extends
 
 class BootstrapVariableTestCase extends DrupalWebTestCase {
 
-  /**
-   * Implementation of setUp().
-   */
   function setUp() {
     parent::setUp('system_test');
   }
 
-  /**
-   * Implementation of getInfo().
-   */
   function getInfo() {
     return array(
       'name' => t('Variable test'),
@@ -160,3 +142,59 @@ class BootstrapVariableTestCase extends 
   }
 
 }
+
+/**
+ * Test hook_boot and hook_exit.
+ */
+class HookBootExitTestCase extends DrupalWebTestCase {
+
+  function getInfo() {
+    return array(
+      'name' => t('Boot and exit hook functionality'),
+      'description' => t('Test that hook_boot() and hook_exit() are called correctly.'),
+      'group' => t('Bootstrap'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('system_test', 'dblog');
+  }
+
+  /**
+   * Test calling of hook_boot() and hook_exit().
+   */
+  function testHookBootExit() {
+    // Test with cache disabled. Boot and exit should always fire. Initialize
+    // the number of hook calls to one since the first call to two since the
+    // first call to drupalGet actually performs two HTTP requests.
+    variable_set('cache', CACHE_DISABLED);
+    $this->drupalGet('');
+    $calls = 2;
+    $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_boot'")->fetchField(), $calls, t('hook_boot called with disabled cache.'));
+    $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_exit'")->fetchField(), $calls, t('hook_exit called with disabled cache.'));
+
+    // Test with normal cache. Boot and exit should be called.
+    variable_set('cache', CACHE_NORMAL);
+    $this->drupalGet('');
+    $calls++;
+    $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_boot'")->fetchField(), $calls, t('hook_boot called with normal cache.'));
+    $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_exit'")->fetchField(), $calls, t('hook_exit called with normal cache.'));
+
+    // Test with aggressive cache. Boot and exit should only fire if there is
+    // no page cached.
+    variable_set('cache', CACHE_AGGRESSIVE);
+    $this->assertTrue(cache_get(url('', array('absolute' => TRUE)), 'cache_page'), t('Page has been cached.'));
+    $this->drupalGet('');
+    $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_boot'")->fetchField(), $calls, t('hook_boot not called with agressive cache and a cached page.'));
+    $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_exit'")->fetchField(), $calls, t('hook_exit not called with agressive cache and a cached page.'));
+
+    // Test with aggressive cache and page cache cleared. Boot and exit should
+    // be called.
+    $this->assertTrue(db_delete('cache_page')->execute(), t('Page cache cleared.'));
+    $this->drupalGet('');
+    $calls++;
+    $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_boot'")->fetchField(), $calls, t('hook_boot called with agressive cache and no cached page.'));
+    $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_exit'")->fetchField(), $calls, t('hook_exit called with agressive cache and no cached page.'));
+  }
+}
+
Index: modules/simpletest/tests/system_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/system_test.module,v
retrieving revision 1.5
diff -u -p -r1.5 system_test.module
--- modules/simpletest/tests/system_test.module	5 Nov 2008 17:06:18 -0000	1.5
+++ modules/simpletest/tests/system_test.module	22 Nov 2008 10:15:42 -0000
@@ -143,6 +143,20 @@ function system_test_modules_uninstalled
 }
 
 /**
+ * Implementation of hook_boot().
+ */
+function system_test_boot() {
+  watchdog('system_test', 'hook_boot');
+}
+
+/**
+ * Implementation of hook_exit().
+ */
+function system_test_exit() {
+  watchdog('system_test', 'hook_exit');
+}
+
+/**
  * Menu callback; generate warnings to test the error handler.
  */
 function system_test_generate_warnings() {
