Cron API: Introduce a $wp_error parameter to functions that write to the cron array.

This allows the functions to return a `WP_Error` object containing more information in case of a problem, instead of just boolean false.

The various `pre_` filters in these functions are also updated so they can return or be passed a `WP_Error` object.

Fixes #49961


git-svn-id: https://develop.svn.wordpress.org/trunk@50143 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
John Blackbourn
2021-02-02 13:47:46 +00:00
parent feb86cb25f
commit 75d2020f3f
2 changed files with 662 additions and 49 deletions

View File

@@ -271,8 +271,12 @@ class Tests_Cron extends WP_UnitTestCase {
// First one works.
$this->assertTrue( wp_schedule_single_event( $ts1, $hook, $args ) );
// Second one is ignored.
// Subsequent ones are ignored.
$this->assertFalse( wp_schedule_single_event( $ts2, $hook, $args ) );
$subsequent = wp_schedule_single_event( $ts2, $hook, $args, true );
$this->assertWPError( $subsequent );
$this->assertSame( 'duplicate_event', $subsequent->get_error_code() );
// The next event should be at +5 minutes, not +3.
$this->assertSame( $ts1, wp_next_scheduled( $hook, $args ) );
@@ -617,6 +621,11 @@ class Tests_Cron extends WP_UnitTestCase {
// Third event fails.
$this->assertFalse( wp_schedule_single_event( $ts3, $hook, $args ) );
// Fourth event fails.
$subsequent = wp_schedule_single_event( $ts3, $hook, $args, true );
$this->assertWPError( $subsequent );
$this->assertSame( 'duplicate_event', $subsequent->get_error_code() );
}
/**
@@ -639,6 +648,12 @@ class Tests_Cron extends WP_UnitTestCase {
// Third event fails.
$this->assertFalse( wp_schedule_single_event( $ts3, $hook, $args ) );
// Fourth event fails.
$subsequent = wp_schedule_single_event( $ts3, $hook, $args, true );
$this->assertWPError( $subsequent );
$this->assertSame( 'duplicate_event', $subsequent->get_error_code() );
}
/**
@@ -659,6 +674,10 @@ class Tests_Cron extends WP_UnitTestCase {
// Events within ten minutes should fail.
$this->assertFalse( wp_schedule_single_event( $ts2, $hook, $args ) );
$this->assertFalse( wp_schedule_single_event( $ts3, $hook, $args ) );
$subsequent = wp_schedule_single_event( $ts3, $hook, $args, true );
$this->assertWPError( $subsequent );
$this->assertSame( 'duplicate_event', $subsequent->get_error_code() );
}
/**
@@ -680,4 +699,411 @@ class Tests_Cron extends WP_UnitTestCase {
$this->assertTrue( wp_schedule_single_event( $ts2, $hook, $args ) );
$this->assertTrue( wp_schedule_single_event( $ts3, $hook, $args ) );
}
/**
* @ticket 49961
*/
public function test_invalid_timestamp_for_event_returns_error() {
$single_event = wp_schedule_single_event( -50, 'hook', array(), true );
$event = wp_schedule_event( -50, 'daily', 'hook', array(), true );
$rescheduled_event = wp_reschedule_event( -50, 'daily', 'hook', array(), true );
$unscheduled_event = wp_unschedule_event( -50, 'hook', array(), true );
$this->assertWPError( $single_event );
$this->assertSame( 'invalid_timestamp', $single_event->get_error_code() );
$this->assertWPError( $event );
$this->assertSame( 'invalid_timestamp', $event->get_error_code() );
$this->assertWPError( $rescheduled_event );
$this->assertSame( 'invalid_timestamp', $rescheduled_event->get_error_code() );
$this->assertWPError( $unscheduled_event );
$this->assertSame( 'invalid_timestamp', $unscheduled_event->get_error_code() );
}
/**
* @ticket 49961
*/
public function test_invalid_recurrence_for_event_returns_error() {
$event = wp_schedule_event( time(), 'invalid', 'hook', array(), true );
$rescheduled_event = wp_reschedule_event( time(), 'invalid', 'hook', array(), true );
$this->assertWPError( $event );
$this->assertSame( 'invalid_schedule', $event->get_error_code() );
$this->assertWPError( $rescheduled_event );
$this->assertSame( 'invalid_schedule', $rescheduled_event->get_error_code() );
}
/**
* @ticket 49961
*/
public function test_disallowed_event_returns_false_when_wp_error_is_set_to_false() {
add_filter( 'schedule_event', '__return_false' );
$single_event = wp_schedule_single_event( time(), 'hook', array() );
$event = wp_schedule_event( time(), 'daily', 'hook', array() );
$rescheduled_event = wp_reschedule_event( time(), 'daily', 'hook', array() );
$this->assertFalse( $single_event );
$this->assertFalse( $event );
$this->assertFalse( $rescheduled_event );
}
/**
* @ticket 49961
*/
public function test_disallowed_event_returns_error_when_wp_error_is_set_to_true() {
add_filter( 'schedule_event', '__return_false' );
$single_event = wp_schedule_single_event( time(), 'hook', array(), true );
$event = wp_schedule_event( time(), 'daily', 'hook', array(), true );
$rescheduled_event = wp_reschedule_event( time(), 'daily', 'hook', array(), true );
$this->assertWPError( $single_event );
$this->assertSame( 'schedule_event_false', $single_event->get_error_code() );
$this->assertWPError( $event );
$this->assertSame( 'schedule_event_false', $event->get_error_code() );
$this->assertWPError( $rescheduled_event );
$this->assertSame( 'schedule_event_false', $rescheduled_event->get_error_code() );
}
/**
* @ticket 49961
*/
public function test_schedule_short_circuit_with_error_returns_false_when_wp_error_is_set_to_false() {
$return_error = function() {
return new WP_Error(
'my_error',
'An error ocurred'
);
};
// Add filters which return a WP_Error:
add_filter( 'pre_schedule_event', $return_error );
add_filter( 'pre_reschedule_event', $return_error );
// Schedule events without the `$wp_error` parameter:
$single_event = wp_schedule_single_event( time(), 'hook', array() );
$event = wp_schedule_event( time(), 'daily', 'hook', array() );
$rescheduled_event = wp_reschedule_event( time(), 'daily', 'hook', array() );
// Ensure boolean false is returned:
$this->assertFalse( $single_event );
$this->assertFalse( $event );
$this->assertFalse( $rescheduled_event );
}
/**
* @ticket 49961
*/
public function test_schedule_short_circuit_with_error_returns_error_when_wp_error_is_set_to_true() {
$return_error = function() {
return new WP_Error(
'my_error',
'An error ocurred'
);
};
// Add filters which return a WP_Error:
add_filter( 'pre_schedule_event', $return_error );
add_filter( 'pre_reschedule_event', $return_error );
// Schedule events with the `$wp_error` parameter:
$single_event = wp_schedule_single_event( time(), 'hook', array(), true );
$event = wp_schedule_event( time(), 'daily', 'hook', array(), true );
$rescheduled_event = wp_reschedule_event( time(), 'daily', 'hook', array(), true );
// Ensure the error object is returned:
$this->assertWPError( $single_event );
$this->assertSame( 'my_error', $single_event->get_error_code() );
$this->assertWPError( $event );
$this->assertSame( 'my_error', $event->get_error_code() );
$this->assertWPError( $rescheduled_event );
$this->assertSame( 'my_error', $rescheduled_event->get_error_code() );
}
/**
* @ticket 49961
*/
public function test_schedule_short_circuit_with_false_returns_false_when_wp_error_is_set_to_false() {
// Add filters which return false:
add_filter( 'pre_schedule_event', '__return_false' );
add_filter( 'pre_reschedule_event', '__return_false' );
// Schedule events without the `$wp_error` parameter:
$single_event = wp_schedule_single_event( time(), 'hook', array() );
$event = wp_schedule_event( time(), 'daily', 'hook', array() );
$rescheduled_event = wp_reschedule_event( time(), 'daily', 'hook', array() );
// Ensure false is returned:
$this->assertFalse( $single_event );
$this->assertFalse( $event );
$this->assertFalse( $rescheduled_event );
}
/**
* @ticket 49961
*/
public function test_schedule_short_circuit_with_false_returns_error_when_wp_error_is_set_to_true() {
// Add filters which return false:
add_filter( 'pre_schedule_event', '__return_false' );
add_filter( 'pre_reschedule_event', '__return_false' );
// Schedule events with the `$wp_error` parameter:
$single_event = wp_schedule_single_event( time(), 'hook', array(), true );
$event = wp_schedule_event( time(), 'daily', 'hook', array(), true );
$rescheduled_event = wp_reschedule_event( time(), 'daily', 'hook', array(), true );
// Ensure an error object is returned:
$this->assertWPError( $single_event );
$this->assertSame( 'pre_schedule_event_false', $single_event->get_error_code() );
$this->assertWPError( $event );
$this->assertSame( 'pre_schedule_event_false', $event->get_error_code() );
$this->assertWPError( $rescheduled_event );
$this->assertSame( 'pre_reschedule_event_false', $rescheduled_event->get_error_code() );
}
/**
* @ticket 49961
* @expectedDeprecated wp_clear_scheduled_hook
*/
public function test_deprecated_argument_usage_of_wp_clear_scheduled_hook() {
add_filter(
'pre_clear_scheduled_hook',
function( $pre, $hook, $args, $wp_error ) {
$this->assertSame( array( 1, 2, 3 ), $args );
$this->assertFalse( $wp_error );
return $pre;
},
10,
4
);
$cleared = wp_clear_scheduled_hook( 'hook', 1, 2, 3 );
$this->assertSame( 0, $cleared );
}
/**
* @ticket 49961
*/
public function test_clear_scheduled_hook_returns_default_pre_filter_error_when_wp_error_is_set_to_true() {
add_filter( 'pre_unschedule_event', '__return_false' );
wp_schedule_single_event( strtotime( '+1 hour' ), 'test_hook' );
wp_schedule_single_event( strtotime( '+2 hours' ), 'test_hook' );
$cleared = wp_clear_scheduled_hook( 'test_hook', array(), true );
$this->assertWPError( $cleared );
$this->assertSame(
array(
'pre_unschedule_event_false',
),
$cleared->get_error_codes()
);
$this->assertCount( 2, $cleared->get_error_messages() );
}
/**
* @ticket 49961
*/
public function test_clear_scheduled_hook_returns_custom_pre_filter_error_when_wp_error_is_set_to_true() {
add_filter(
'pre_unschedule_event',
function( $pre ) {
return new WP_Error( 'error_code', 'error message' );
}
);
wp_schedule_single_event( strtotime( '+1 hour' ), 'test_hook' );
wp_schedule_single_event( strtotime( '+2 hours' ), 'test_hook' );
$cleared = wp_clear_scheduled_hook( 'test_hook', array(), true );
$this->assertWPError( $cleared );
$this->assertSame(
array(
'error_code',
),
$cleared->get_error_codes()
);
$this->assertSame(
array(
'error message',
'error message',
),
$cleared->get_error_messages()
);
}
/**
* @ticket 49961
*/
public function test_unschedule_short_circuit_with_error_returns_false_when_wp_error_is_set_to_false() {
$return_error = function() {
return new WP_Error(
'my_error',
'An error ocurred'
);
};
// Add a filter which returns a WP_Error:
add_filter( 'pre_unschedule_hook', $return_error );
// Unschedule a hook without the `$wp_error` parameter:
$result = wp_unschedule_hook( 'hook' );
// Ensure boolean false is returned:
$this->assertFalse( $result );
}
/**
* @ticket 49961
*/
public function test_unschedule_short_circuit_with_error_returns_error_when_wp_error_is_set_to_true() {
$return_error = function() {
return new WP_Error(
'my_error',
'An error ocurred'
);
};
// Add a filter which returns a WP_Error:
add_filter( 'pre_unschedule_hook', $return_error );
// Unschedule a hook with the `$wp_error` parameter:
$result = wp_unschedule_hook( 'hook', true );
// Ensure the error object is returned:
$this->assertWPError( $result );
$this->assertSame( 'my_error', $result->get_error_code() );
}
/**
* @ticket 49961
*/
public function test_unschedule_short_circuit_with_false_returns_false_when_wp_error_is_set_to_false() {
// Add a filter which returns false:
add_filter( 'pre_unschedule_hook', '__return_false' );
// Unschedule a hook without the `$wp_error` parameter:
$result = wp_unschedule_hook( 'hook' );
// Ensure false is returned:
$this->assertFalse( $result );
}
/**
* @ticket 49961
*/
public function test_unschedule_short_circuit_with_false_returns_error_when_wp_error_is_set_to_true() {
// Add a filter which returns false:
add_filter( 'pre_unschedule_hook', '__return_false' );
// Unchedule a hook with the `$wp_error` parameter:
$result = wp_unschedule_hook( 'hook', true );
// Ensure an error object is returned:
$this->assertWPError( $result );
$this->assertSame( 'pre_unschedule_hook_false', $result->get_error_code() );
}
/**
* @ticket 49961
*/
public function test_cron_array_error_is_returned_when_scheduling_single_event() {
// Force update_option() to fail by setting the new value to match the existing:
add_filter(
'pre_update_option_cron',
function() {
return get_option( 'cron' );
}
);
// Attempt to schedule a valid event:
$event = wp_schedule_single_event( time(), 'hook', array(), true );
// Ensure an error object is returned:
$this->assertWPError( $event );
$this->assertSame( 'could_not_set', $event->get_error_code() );
}
/**
* @ticket 49961
*/
public function test_cron_array_error_is_returned_when_scheduling_event() {
// Force update_option() to fail by setting the new value to match the existing:
add_filter(
'pre_update_option_cron',
function() {
return get_option( 'cron' );
}
);
// Attempt to schedule a valid event:
$event = wp_schedule_event( time(), 'daily', 'hook', array(), true );
// Ensure an error object is returned:
$this->assertWPError( $event );
$this->assertSame( 'could_not_set', $event->get_error_code() );
}
/**
* @ticket 49961
*/
public function test_cron_array_error_is_returned_when_unscheduling_hook() {
// Schedule a valid event:
$event = wp_schedule_event( strtotime( '+1 hour' ), 'daily', 'hook', array(), true );
// Force update_option() to fail by setting the new value to match the existing:
add_filter(
'pre_update_option_cron',
function() {
return get_option( 'cron' );
}
);
// Attempt to unschedule the hook:
$unscheduled = wp_unschedule_hook( 'hook', true );
// Ensure an error object is returned:
$this->assertTrue( $event );
$this->assertWPError( $unscheduled );
$this->assertSame( 'could_not_set', $unscheduled->get_error_code() );
}
/**
* @ticket 49961
*/
public function test_cron_array_error_is_returned_when_unscheduling_event() {
// Schedule a valid event:
$event = wp_schedule_event( strtotime( '+1 hour' ), 'daily', 'hook', array(), true );
// Force update_option() to fail by setting the new value to match the existing:
add_filter(
'pre_update_option_cron',
function() {
return get_option( 'cron' );
}
);
// Attempt to unschedule the event:
$unscheduled = wp_unschedule_event( wp_next_scheduled( 'hook' ), 'hook', array(), true );
// Ensure an error object is returned:
$this->assertTrue( $event );
$this->assertWPError( $unscheduled );
$this->assertSame( 'could_not_set', $unscheduled->get_error_code() );
}
}