? 600836-timcosgrove-batch-never-finishes.patch ? 600836_batch_large_percentage.patch ? sites/all/modules/admin_menu ? sites/all/modules/coder ? sites/all/modules/examples ? sites/all/modules/views ? sites/all/modules/views_bulk_operations ? sites/default/files ? sites/default/private ? sites/default/settings.php Index: includes/batch.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/batch.inc,v retrieving revision 1.50 diff -u -p -r1.50 batch.inc --- includes/batch.inc 17 Feb 2010 22:44:51 -0000 1.50 +++ includes/batch.inc 22 Apr 2010 23:53:05 -0000 @@ -285,7 +285,7 @@ function _batch_process() { ); call_user_func_array($function, array_merge($args, array(&$batch_context))); - if ($finished == 1) { + if ($finished >= 1) { // Make sure this step is not counted twice when computing $current. $finished = 0; // Remove the processed operation and clear the sandbox. Index: modules/color/color.module =================================================================== RCS file: /cvs/drupal/drupal/modules/color/color.module,v retrieving revision 1.84 diff -u -p -r1.84 color.module --- modules/color/color.module 22 Apr 2010 05:18:21 -0000 1.84 +++ modules/color/color.module 22 Apr 2010 23:53:05 -0000 @@ -115,10 +115,17 @@ function _color_page_alter(&$vars) { * Retrieve the color.module info for a particular theme. */ function color_get_info($theme) { + static $theme_info = array(); + + if (isset($theme_info[$theme])) { + return $theme_info[$theme]; + } + $path = drupal_get_path('theme', $theme); $file = DRUPAL_ROOT . '/' . $path . '/color/color.inc'; if ($path && file_exists($file)) { include $file; + $theme_info[$theme] = $info; return $info; } } Index: modules/simpletest/tests/batch.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/batch.test,v retrieving revision 1.8 diff -u -p -r1.8 batch.test --- modules/simpletest/tests/batch.test 8 Jan 2010 06:36:34 -0000 1.8 +++ modules/simpletest/tests/batch.test 22 Apr 2010 23:53:06 -0000 @@ -27,7 +27,7 @@ class BatchProcessingTestCase extends Dr */ function testBatchNoForm() { // Displaying the page triggers batch 1. - $this->drupalGet('batch_test/no_form'); + $this->drupalGet('batch-test/no-form'); $this->assertBatchMessages($this->_resultMessages(1), t('Batch for step 2 performed successfully.')); $this->assertEqual(batch_test_stack(), $this->_resultStack('batch_1'), t('Execution order was correct.')); $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.')); @@ -39,34 +39,34 @@ class BatchProcessingTestCase extends Dr function testBatchForm() { // Batch 0: no operation. $edit = array('batch' => 'batch_0'); - $this->drupalPost('batch_test/simple', $edit, 'Submit'); + $this->drupalPost('batch-test/simple', $edit, 'Submit'); $this->assertBatchMessages($this->_resultMessages('batch_0'), t('Batch with no operation performed successfully.')); $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.')); // Batch 1: several simple operations. $edit = array('batch' => 'batch_1'); - $this->drupalPost('batch_test/simple', $edit, 'Submit'); + $this->drupalPost('batch-test/simple', $edit, 'Submit'); $this->assertBatchMessages($this->_resultMessages('batch_1'), t('Batch with simple operations performed successfully.')); $this->assertEqual(batch_test_stack(), $this->_resultStack('batch_1'), t('Execution order was correct.')); $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.')); // Batch 2: one multistep operation. $edit = array('batch' => 'batch_2'); - $this->drupalPost('batch_test/simple', $edit, 'Submit'); + $this->drupalPost('batch-test/simple', $edit, 'Submit'); $this->assertBatchMessages($this->_resultMessages('batch_2'), t('Batch with multistep operation performed successfully.')); $this->assertEqual(batch_test_stack(), $this->_resultStack('batch_2'), t('Execution order was correct.')); $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.')); // Batch 3: simple + multistep combined. $edit = array('batch' => 'batch_3'); - $this->drupalPost('batch_test/simple', $edit, 'Submit'); + $this->drupalPost('batch-test/simple', $edit, 'Submit'); $this->assertBatchMessages($this->_resultMessages('batch_3'), t('Batch with simple and multistep operations performed successfully.')); $this->assertEqual(batch_test_stack(), $this->_resultStack('batch_3'), t('Execution order was correct.')); $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.')); // Batch 4: nested batch. $edit = array('batch' => 'batch_4'); - $this->drupalPost('batch_test/simple', $edit, 'Submit'); + $this->drupalPost('batch-test/simple', $edit, 'Submit'); $this->assertBatchMessages($this->_resultMessages('batch_4'), t('Nested batch performed successfully.')); $this->assertEqual(batch_test_stack(), $this->_resultStack('batch_4'), t('Execution order was correct.')); $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.')); @@ -76,7 +76,7 @@ class BatchProcessingTestCase extends Dr * Test batches defined in a multistep form. */ function testBatchFormMultistep() { - $this->drupalGet('batch_test/multistep'); + $this->drupalGet('batch-test/multistep'); $this->assertText('step 1', t('Form is displayed in step 1.')); // First step triggers batch 1. @@ -100,7 +100,7 @@ class BatchProcessingTestCase extends Dr // handlers. Each submit handler modify the submitted 'value'. $value = rand(0, 255); $edit = array('value' => $value); - $this->drupalPost('batch_test/chained', $edit, 'Submit'); + $this->drupalPost('batch-test/chained', $edit, 'Submit'); // Check that result messages are present and in the correct order. $this->assertBatchMessages($this->_resultMessages('chained'), t('Batches defined in separate submit handlers performed successfully.')); // The stack contains execution order of batch callbacks and submit @@ -118,7 +118,7 @@ class BatchProcessingTestCase extends Dr // Batches 1, 2 and 3 are triggered in sequence by different submit // handlers. Each submit handler modify the submitted 'value'. $value = rand(0, 255); - $this->drupalGet('batch_test/programmatic/' . $value); + $this->drupalGet('batch-test/programmatic/' . $value); // Check that result messages are present and in the correct order. $this->assertBatchMessages($this->_resultMessages('chained'), t('Batches defined in separate submit handlers performed successfully.')); // The stack contains execution order of batch callbacks and submit @@ -134,11 +134,24 @@ class BatchProcessingTestCase extends Dr // Displaying the page triggers a batch that programmatically submits a // form. $value = rand(0, 255); - $this->drupalGet('batch_test/nested_programmatic/' . $value); + $this->drupalGet('batch-test/nested-programmatic/' . $value); $this->assertEqual(batch_test_stack(), array('mock form submitted with value = ' . $value), t('drupal_form_submit() ran successfully within a batch operation.')); } /** + * Test batches that return $context['finished'] > 1 do in fact complete. + * see http://drupal.org/node/600836 + */ + function testBatchLargePercentage() { + // Displaying the page triggers batch 5. + $this->drupalGet('batch-test/large-percentage'); + $this->assertBatchMessages($this->_resultMessages(1), t('Batch for step 2 performed successfully.')); + $this->assertEqual(batch_test_stack(), $this->_resultStack('batch_5'), t('Execution order was correct.')); + $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.')); + } + + + /** * Will trigger a pass if the texts were found in order in the raw content. * * @param $texts @@ -197,6 +210,12 @@ class BatchProcessingTestCase extends Dr $stack = array_merge($stack, $this->_resultStack('batch_2')); break; + case 'batch_5': + for ($i = 1; $i <= 10; $i++) { + $stack[] = "op 5 id $i"; + } + break; + case 'chained': $stack[] = 'submit handler 1'; $stack[] = 'value = ' . $value; @@ -242,6 +261,10 @@ class BatchProcessingTestCase extends Dr $messages = array_merge($messages, $this->_resultMessages('batch_2')); break; + case 'batch_5': + $messages[] = 'results for batch 5
op 1: processed 10 elements. $context[\'finished\'] > 1 returned from batch process, with success.'; + break; + case 'chained': $messages = array_merge($messages, $this->_resultMessages('batch_1')); $messages = array_merge($messages, $this->_resultMessages('batch_2')); @@ -280,7 +303,7 @@ class BatchPageTestCase extends DrupalWe // theme that was used during batch execution (which the batch callback // function saved as a variable) matches the theme used on the // administrative page. - $this->drupalGet('admin/batch_test/test_theme'); + $this->drupalGet('admin/batch-test/test-theme'); // The stack should contain the name of the the used on the progress page. $this->assertEqual(batch_test_stack(), array('seven'), t('A progressive batch correctly uses the theme of the page that started the batch.')); } Index: modules/simpletest/tests/batch_test.callbacks.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/batch_test.callbacks.inc,v retrieving revision 1.1 diff -u -p -r1.1 batch_test.callbacks.inc --- modules/simpletest/tests/batch_test.callbacks.inc 8 Jan 2010 06:36:34 -0000 1.1 +++ modules/simpletest/tests/batch_test.callbacks.inc 22 Apr 2010 23:53:06 -0000 @@ -12,6 +12,7 @@ */ function _batch_test_callback_1($id, $sleep, &$context) { // No-op, but ensure the batch take a couple iterations. + // batch needs time to run for the test, so sleep a bit. usleep($sleep); // Track execution, and store some result for post-processing in the // 'finished' callback. @@ -32,7 +33,8 @@ function _batch_test_callback_2($start, // Process by groups of 5 (arbitrary value). $limit = 5; for ($i = 0; $i < $limit && $context['sandbox']['count'] < $total; $i++) { - // No-op, but ensure the batch take a couple iterations. + // No-op, but ensure the batch take a couple iterations. + // batch needs time to run for the test, so sleep a bit. usleep($sleep); // Track execution, and store some result for post-processing in the // 'finished' callback. @@ -52,6 +54,21 @@ function _batch_test_callback_2($start, } /** + * Simple batch operation. + */ +function _batch_test_callback_5($id, $sleep, &$context) { + // No-op, but ensure the batch take a couple iterations. + // batch needs time to run for the test, so sleep a bit. + usleep($sleep); + // Track execution, and store some result for post-processing in the + // 'finished' callback. + batch_test_stack("op 5 id $id"); + $context['results'][5][] = $id; + // this test is to test finished > 1 + $context['finished'] = 3.14; +} + +/** * Batch operation setting up its own batch. */ function _batch_test_nested_batch_callback() { @@ -116,3 +133,10 @@ function _batch_test_finished_3($success function _batch_test_finished_4($success, $results, $operations) { _batch_test_finished_helper(4, $success, $results, $operations); } + +/** + * 'finished' callback for batch 5. + */ +function _batch_test_finished_5($success, $results, $operations) { + _batch_test_finished_helper(5, $success, $results, $operations); +} Index: modules/simpletest/tests/batch_test.module =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/batch_test.module,v retrieving revision 1.1 diff -u -p -r1.1 batch_test.module --- modules/simpletest/tests/batch_test.module 8 Jan 2010 06:36:34 -0000 1.1 +++ modules/simpletest/tests/batch_test.module 22 Apr 2010 23:53:06 -0000 @@ -12,20 +12,20 @@ function batch_test_menu() { $items = array(); - $items['batch_test'] = array( + $items['batch-test'] = array( 'title' => 'Batch test', 'page callback' => 'drupal_get_form', 'page arguments' => array('batch_test_simple_form'), 'access callback' => TRUE, ); // Simple form: one submit handler, setting a batch. - $items['batch_test/simple'] = array( + $items['batch-test/simple'] = array( 'title' => 'Simple', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => 0, ); // Multistep form: two steps, each setting a batch. - $items['batch_test/multistep'] = array( + $items['batch-test/multistep'] = array( 'title' => 'Multistep', 'page callback' => 'drupal_get_form', 'page arguments' => array('batch_test_multistep_form'), @@ -34,7 +34,7 @@ function batch_test_menu() { 'weight' => 1, ); // Chained form: four submit handlers, several of which set a batch. - $items['batch_test/chained'] = array( + $items['batch-test/chained'] = array( 'title' => 'Chained', 'page callback' => 'drupal_get_form', 'page arguments' => array('batch_test_chained_form'), @@ -44,7 +44,7 @@ function batch_test_menu() { ); // Programmatic form: the page submits the 'Chained' form through // drupal_form_submit(). - $items['batch_test/programmatic'] = array( + $items['batch-test/programmatic'] = array( 'title' => 'Programmatic', 'page callback' => 'batch_test_programmatic', 'access callback' => TRUE, @@ -52,41 +52,49 @@ function batch_test_menu() { 'weight' => 3, ); // No form: fire a batch simply by accessing a page. - $items['batch_test/no_form'] = array( + $items['batch-test/no-form'] = array( 'title' => 'Simple page', 'page callback' => 'batch_test_no_form', 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, 'weight' => 4, ); + // No form: fire a batch; return > 100% complete + $items['batch-test/large-percentage'] = array( + 'title' => 'Simple page with batch over 100% complete', + 'page callback' => 'batch_test_large_percentage', + 'access callback' => TRUE, + 'type' => MENU_LOCAL_TASK, + 'weight' => 5, + ); // Tests programmatic form submission within a batch operation. - $items['batch_test/nested_programmatic'] = array( + $items['batch-test/nested-programmatic'] = array( 'title' => 'Nested programmatic', 'page callback' => 'batch_test_nested_drupal_form_submit', 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, - 'weight' => 5, + 'weight' => 6, ); // Landing page to test redirects. - $items['batch_test/redirect'] = array( + $items['batch-test/redirect'] = array( 'title' => 'Redirect', 'page callback' => 'batch_test_redirect_page', 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, - 'weight' => 6, + 'weight' => 7, ); // // This item lives under 'admin' so that the page uses the admin theme. - $items['admin/batch_test/test_theme'] = array( + $items['admin/batch-test/test-theme'] = array( 'page callback' => 'batch_test_theme_batch', 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); return $items; -} +} -/** + /** * Simple form. */ function batch_test_simple_form() { @@ -118,7 +126,7 @@ function batch_test_simple_form_submit($ $function = '_batch_test_' . $form_state['values']['batch']; batch_set($function()); - $form_state['redirect'] = 'batch_test/redirect'; + $form_state['redirect'] = 'batch-test/redirect'; } @@ -162,7 +170,7 @@ function batch_test_multistep_form_submi } // This will only be effective on the last step. - $form_state['redirect'] = 'batch_test/redirect'; + $form_state['redirect'] = 'batch-test/redirect'; } /** @@ -244,7 +252,7 @@ function batch_test_chained_form_submit_ batch_set(_batch_test_batch_3()); // This is the redirect that should prevail. - $form_state['redirect'] = 'batch_test/redirect'; + $form_state['redirect'] = 'batch-test/redirect'; } /** @@ -267,7 +275,7 @@ function batch_test_nested_drupal_form_s array('_batch_test_nested_drupal_form_submit_callback', array($value)), ); batch_set($batch); - batch_process('batch_test/redirect'); + batch_process('batch-test/redirect'); } /** @@ -307,7 +315,17 @@ function batch_test_no_form() { batch_test_stack(NULL, TRUE); batch_set(_batch_test_batch_1()); - batch_process('batch_test/redirect'); + batch_process('batch-test/redirect'); +} + +/** + * Menu callback: fire a batch process without a form submission. + */ +function batch_test_large_percentage() { + batch_test_stack(NULL, TRUE); + + batch_set(_batch_test_batch_5()); + batch_process('batch-test/redirect'); } /** @@ -433,6 +451,28 @@ function _batch_test_batch_4() { } /** + * Batch 5: repeats a simple operation. + * + * Operations: op 1 from 1 to 10. + */ +function _batch_test_batch_5() { + // Ensure the batch takes at least two iterations. + $total = 10; + $sleep = (1000000 / $total) * 2; + + $operations = array(); + for ($i = 1; $i <= $total; $i++) { + $operations[] = array('_batch_test_callback_5', array($i, $sleep)); + } + $batch = array( + 'operations' => $operations, + 'finished' => '_batch_test_finished_5', + 'file' => drupal_get_path('module', 'batch_test'). '/batch_test.callbacks.inc', + ); + return $batch; +} + +/** * Menu callback: run a batch for testing theme used on the progress page. */ function batch_test_theme_batch() { @@ -443,7 +483,7 @@ function batch_test_theme_batch() { ), ); batch_set($batch); - batch_process('batch_test/redirect'); + batch_process('batch-test/redirect'); } /**