installed plugin WPScan version 1.15.1

This commit is contained in:
2021-05-13 11:27:50 +00:00
committed by Gitium
parent 2b403ab680
commit e0e2392c3c
193 changed files with 30878 additions and 0 deletions

View File

@ -0,0 +1,19 @@
<?php
/**
* ActionScheduler_Mock_AsyncRequest_QueueRunner
*/
defined( 'ABSPATH' ) || exit;
/**
* ActionScheduler_Mock_AsyncRequest_QueueRunner class.
*/
class ActionScheduler_Mock_AsyncRequest_QueueRunner extends ActionScheduler_AsyncRequest_QueueRunner {
/**
* Do not run queues via async requests.
*/
protected function allow() {
return false;
}
}

View File

@ -0,0 +1,35 @@
<?php
/**
* ActionScheduler_Mocker
*/
defined( 'ABSPATH' ) || exit;
/**
* ActionScheduler_Mocker class.
*/
class ActionScheduler_Mocker {
/**
* Do not run queues via async requests.
*
* @param ActionScheduler_Store $store
*/
public static function get_queue_runner( ActionScheduler_Store $store = null ) {
if ( ! $store ) {
$store = ActionScheduler_Store::instance();
}
return new ActionScheduler_QueueRunner( $store, null, null, self::get_async_request_queue_runner( $store ) );
}
/**
* Get an instance of the mock queue runner
*
* @param ActionScheduler_Store $store
*/
protected static function get_async_request_queue_runner( ActionScheduler_Store $store ) {
return new ActionScheduler_Mock_AsyncRequest_QueueRunner( $store );
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Class ActionScheduler_UnitTestCase
*/
class ActionScheduler_UnitTestCase extends WP_UnitTestCase {
protected $existing_timezone;
/**
* Counts the number of test cases executed by run(TestResult result).
*
* @return int
*/
public function count() {
return 'UTC' == date_default_timezone_get() ? 2 : 3;
}
/**
* We want to run every test multiple times using a different timezone to make sure
* that they are unaffected by changes to PHP's timezone.
*/
public function run( PHPUnit_Framework_TestResult $result = NULL ){
if ($result === NULL) {
$result = $this->createResult();
}
if ( 'UTC' != ( $this->existing_timezone = date_default_timezone_get() ) ) {
date_default_timezone_set( 'UTC' );
$result->run( $this );
}
date_default_timezone_set( 'Pacific/Fiji' ); // UTC+12
$result->run( $this );
date_default_timezone_set( 'Pacific/Tahiti' ); // UTC-10: it's a magical place
$result->run( $this );
date_default_timezone_set( $this->existing_timezone );
return $result;
}
}

View File

@ -0,0 +1,100 @@
<?php
/**
* @group timezone
*/
class ActionScheduler_TimezoneHelper_Test extends ActionScheduler_UnitTestCase {
/**
* Ensure that the timezone string we expect works properly.
*
* @dataProvider local_timezone_provider
*
* @param $timezone_string
*/
public function test_local_timezone_strings( $timezone_string ) {
$timezone_filter = function ( $tz ) use ( $timezone_string ) {
return $timezone_string;
};
add_filter( 'option_timezone_string', $timezone_filter );
$date = new ActionScheduler_DateTime();
$timezone = ActionScheduler_TimezoneHelper::set_local_timezone( $date )->getTimezone();
$this->assertInstanceOf( 'DateTimeZone', $timezone );
$this->assertEquals( $timezone_string, $timezone->getName() );
remove_filter( 'option_timezone_string', $timezone_filter );
}
public function local_timezone_provider() {
return array(
array( 'America/New_York' ),
array( 'Australia/Melbourne' ),
array( 'UTC' ),
);
}
/**
* Ensure that most GMT offsets don't return UTC as the timezone.
*
* @dataProvider local_timezone_offsets_provider
*
* @param $gmt_offset
*/
public function test_local_timezone_offsets( $gmt_offset ) {
$gmt_filter = function ( $gmt ) use ( $gmt_offset ) {
return $gmt_offset;
};
$date = new ActionScheduler_DateTime();
add_filter( 'option_gmt_offset', $gmt_filter );
ActionScheduler_TimezoneHelper::set_local_timezone( $date );
remove_filter( 'option_gmt_offset', $gmt_filter );
$offset_in_seconds = $gmt_offset * HOUR_IN_SECONDS;
$this->assertEquals( $offset_in_seconds, $date->getOffset() );
$this->assertEquals( $offset_in_seconds, $date->getOffsetTimestamp() - $date->getTimestamp() );
}
public function local_timezone_offsets_provider() {
return array(
array( '-11' ),
array( '-10.5' ),
array( '-10' ),
array( '-9' ),
array( '-8' ),
array( '-7' ),
array( '-6' ),
array( '-5' ),
array( '-4.5' ),
array( '-4' ),
array( '-3.5' ),
array( '-3' ),
array( '-2' ),
array( '-1' ),
array( '1' ),
array( '1.5' ),
array( '2' ),
array( '3' ),
array( '4' ),
array( '5' ),
array( '5.5' ),
array( '5.75' ),
array( '6' ),
array( '7' ),
array( '8' ),
array( '8.5' ),
array( '9' ),
array( '9.5' ),
array( '10' ),
array( '10.5' ),
array( '11' ),
array( '11.5' ),
array( '12' ),
array( '13' ),
);
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* Class ActionScheduler_Action_Test
* @group actions
*/
class ActionScheduler_Action_Test extends ActionScheduler_UnitTestCase {
public function test_set_schedule() {
$time = as_get_datetime_object();
$schedule = new ActionScheduler_SimpleSchedule($time);
$action = new ActionScheduler_Action('my_hook', array(), $schedule);
$this->assertEquals( $schedule, $action->get_schedule() );
}
public function test_null_schedule() {
$action = new ActionScheduler_Action('my_hook');
$this->assertInstanceOf( 'ActionScheduler_NullSchedule', $action->get_schedule() );
}
public function test_set_hook() {
$action = new ActionScheduler_Action('my_hook');
$this->assertEquals( 'my_hook', $action->get_hook() );
}
public function test_args() {
$action = new ActionScheduler_Action('my_hook');
$this->assertEmpty($action->get_args());
$action = new ActionScheduler_Action('my_hook', array(5,10,15));
$this->assertEqualSets(array(5,10,15), $action->get_args());
}
public function test_set_group() {
$action = new ActionScheduler_Action('my_hook', array(), NULL, 'my_group');
$this->assertEquals('my_group', $action->get_group());
}
public function test_execute() {
$mock = new MockAction();
$random = md5(rand());
add_action( $random, array( $mock, 'action' ) );
$action = new ActionScheduler_Action( $random, array($random) );
$action->execute();
remove_action( $random, array( $mock, 'action' ) );
$this->assertEquals( 1, $mock->get_call_count() );
$events = $mock->get_events();
$event = reset($events);
$this->assertEquals( $random, reset($event['args']) );
}
}

View File

@ -0,0 +1,16 @@
<?php
/**
* Class ActionScheduler_NullAction_Test
* @group actions
*/
class ActionScheduler_NullAction_Test extends ActionScheduler_UnitTestCase {
public function test_null_action() {
$action = new ActionScheduler_NullAction();
$this->assertEmpty($action->get_hook());
$this->assertEmpty($action->get_args());
$this->assertNull( $action->get_schedule()->get_date() );
}
}

View File

@ -0,0 +1,26 @@
<?php
/**
* Class ActionScheduler_DBStoreMigrator_Test
* @group tables
*/
class ActionScheduler_DBStoreMigrator_Test extends ActionScheduler_UnitTestCase {
public function test_create_action_with_last_attempt_date() {
$scheduled_date = as_get_datetime_object( strtotime( '-24 hours' ) );
$last_attempt_date = as_get_datetime_object( strtotime( '-23 hours' ) );
$action = new ActionScheduler_FinishedAction( 'my_hook', [], new ActionScheduler_SimpleSchedule( $scheduled_date ) );
$store = new ActionScheduler_DBStoreMigrator();
$action_id = $store->save_action( $action, null, $last_attempt_date );
$action_date = $store->get_date( $action_id );
$this->assertEquals( $last_attempt_date->format( 'U' ), $action_date->format( 'U' ) );
$action_id = $store->save_action( $action, $scheduled_date, $last_attempt_date );
$action_date = $store->get_date( $action_id );
$this->assertEquals( $last_attempt_date->format( 'U' ), $action_date->format( 'U' ) );
}
}

View File

@ -0,0 +1,444 @@
<?php
/**
* Class ActionScheduler_DBStore_Test
* @group tables
*/
class ActionScheduler_DBStore_Test extends ActionScheduler_UnitTestCase {
public function test_create_action() {
$time = as_get_datetime_object();
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule );
$store = new ActionScheduler_DBStore();
$action_id = $store->save_action( $action );
$this->assertNotEmpty( $action_id );
}
public function test_create_action_with_scheduled_date() {
$time = as_get_datetime_object( strtotime( '-1 week' ) );
$action = new ActionScheduler_Action( 'my_hook', [], new ActionScheduler_SimpleSchedule( $time ) );
$store = new ActionScheduler_DBStore();
$action_id = $store->save_action( $action, $time );
$action_date = $store->get_date( $action_id );
$this->assertEquals( $time->format( 'U' ), $action_date->format( 'U' ) );
}
public function test_retrieve_action() {
$time = as_get_datetime_object();
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule, 'my_group' );
$store = new ActionScheduler_DBStore();
$action_id = $store->save_action( $action );
$retrieved = $store->fetch_action( $action_id );
$this->assertEquals( $action->get_hook(), $retrieved->get_hook() );
$this->assertEqualSets( $action->get_args(), $retrieved->get_args() );
$this->assertEquals( $action->get_schedule()->get_date()->format( 'U' ), $retrieved->get_schedule()->get_date()->format( 'U' ) );
$this->assertEquals( $action->get_group(), $retrieved->get_group() );
}
public function test_cancel_action() {
$time = as_get_datetime_object();
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule, 'my_group' );
$store = new ActionScheduler_DBStore();
$action_id = $store->save_action( $action );
$store->cancel_action( $action_id );
$fetched = $store->fetch_action( $action_id );
$this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
}
public function test_cancel_actions_by_hook() {
$store = new ActionScheduler_DBStore();
$actions = [];
$hook = 'by_hook_test';
for ( $day = 1; $day <= 3; $day++ ) {
$delta = sprintf( '+%d day', $day );
$time = as_get_datetime_object( $delta );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( $hook, [], $schedule, 'my_group' );
$actions[] = $store->save_action( $action );
}
$store->cancel_actions_by_hook( $hook );
foreach ( $actions as $action_id ) {
$fetched = $store->fetch_action( $action_id );
$this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
}
}
public function test_cancel_actions_by_group() {
$store = new ActionScheduler_DBStore();
$actions = [];
$group = 'by_group_test';
for ( $day = 1; $day <= 3; $day++ ) {
$delta = sprintf( '+%d day', $day );
$time = as_get_datetime_object( $delta );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule, $group );
$actions[] = $store->save_action( $action );
}
$store->cancel_actions_by_group( $group );
foreach ( $actions as $action_id ) {
$fetched = $store->fetch_action( $action_id );
$this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
}
}
public function test_claim_actions() {
$created_actions = [];
$store = new ActionScheduler_DBStore();
for ( $i = 3; $i > - 3; $i -- ) {
$time = as_get_datetime_object( $i . ' hours' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [ $i ], $schedule, 'my_group' );
$created_actions[] = $store->save_action( $action );
}
$claim = $store->stake_claim();
$this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
$this->assertCount( 3, $claim->get_actions() );
$this->assertEqualSets( array_slice( $created_actions, 3, 3 ), $claim->get_actions() );
}
public function test_claim_actions_order() {
$store = new ActionScheduler_DBStore();
$schedule = new ActionScheduler_SimpleSchedule( as_get_datetime_object( '-1 hour' ) );
$created_actions = array(
$store->save_action( new ActionScheduler_Action( 'my_hook', array( 1 ), $schedule, 'my_group' ) ),
$store->save_action( new ActionScheduler_Action( 'my_hook', array( 1 ), $schedule, 'my_group' ) ),
);
$claim = $store->stake_claim();
$this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
// Verify uniqueness of action IDs.
$this->assertEquals( 2, count( array_unique( $created_actions ) ) );
// Verify the count and order of the actions.
$claimed_actions = $claim->get_actions();
$this->assertCount( 2, $claimed_actions );
$this->assertEquals( $created_actions, $claimed_actions );
// Verify the reversed order doesn't pass.
$reversed_actions = array_reverse( $created_actions );
$this->assertNotEquals( $reversed_actions, $claimed_actions );
}
public function test_claim_actions_by_hooks() {
$created_actions = $created_actions_by_hook = [];
$store = new ActionScheduler_DBStore();
$unique_hook_one = 'my_unique_hook_one';
$unique_hook_two = 'my_unique_hook_two';
$unique_hooks = array(
$unique_hook_one,
$unique_hook_two,
);
for ( $i = 3; $i > - 3; $i -- ) {
foreach ( $unique_hooks as $unique_hook ) {
$time = as_get_datetime_object( $i . ' hours' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( $unique_hook, [ $i ], $schedule, 'my_group' );
$action_id = $store->save_action( $action );
$created_actions[] = $created_actions_by_hook[ $unique_hook ][] = $action_id;
}
}
$claim = $store->stake_claim( 10, null, $unique_hooks );
$this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
$this->assertCount( 6, $claim->get_actions() );
$this->assertEqualSets( array_slice( $created_actions, 6, 6 ), $claim->get_actions() );
$store->release_claim( $claim );
$claim = $store->stake_claim( 10, null, array( $unique_hook_one ) );
$this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
$this->assertCount( 3, $claim->get_actions() );
$this->assertEqualSets( array_slice( $created_actions_by_hook[ $unique_hook_one ], 3, 3 ), $claim->get_actions() );
$store->release_claim( $claim );
$claim = $store->stake_claim( 10, null, array( $unique_hook_two ) );
$this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
$this->assertCount( 3, $claim->get_actions() );
$this->assertEqualSets( array_slice( $created_actions_by_hook[ $unique_hook_two ], 3, 3 ), $claim->get_actions() );
}
public function test_claim_actions_by_group() {
$created_actions = [];
$store = new ActionScheduler_DBStore();
$unique_group_one = 'my_unique_group_one';
$unique_group_two = 'my_unique_group_two';
$unique_groups = array(
$unique_group_one,
$unique_group_two,
);
for ( $i = 3; $i > - 3; $i -- ) {
foreach ( $unique_groups as $unique_group ) {
$time = as_get_datetime_object( $i . ' hours' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [ $i ], $schedule, $unique_group );
$created_actions[ $unique_group ][] = $store->save_action( $action );
}
}
$claim = $store->stake_claim( 10, null, array(), $unique_group_one );
$this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
$this->assertCount( 3, $claim->get_actions() );
$this->assertEqualSets( array_slice( $created_actions[ $unique_group_one ], 3, 3 ), $claim->get_actions() );
$store->release_claim( $claim );
$claim = $store->stake_claim( 10, null, array(), $unique_group_two );
$this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
$this->assertCount( 3, $claim->get_actions() );
$this->assertEqualSets( array_slice( $created_actions[ $unique_group_two ], 3, 3 ), $claim->get_actions() );
}
public function test_claim_actions_by_hook_and_group() {
$created_actions = $created_actions_by_hook = [];
$store = new ActionScheduler_DBStore();
$unique_hook_one = 'my_other_unique_hook_one';
$unique_hook_two = 'my_other_unique_hook_two';
$unique_hooks = array(
$unique_hook_one,
$unique_hook_two,
);
$unique_group_one = 'my_other_other_unique_group_one';
$unique_group_two = 'my_other_unique_group_two';
$unique_groups = array(
$unique_group_one,
$unique_group_two,
);
for ( $i = 3; $i > - 3; $i -- ) {
foreach ( $unique_hooks as $unique_hook ) {
foreach ( $unique_groups as $unique_group ) {
$time = as_get_datetime_object( $i . ' hours' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( $unique_hook, [ $i ], $schedule, $unique_group );
$action_id = $store->save_action( $action );
$created_actions[ $unique_group ][] = $action_id;
$created_actions_by_hook[ $unique_hook ][ $unique_group ][] = $action_id;
}
}
}
/** Test Both Hooks with Each Group */
$claim = $store->stake_claim( 10, null, $unique_hooks, $unique_group_one );
$this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
$this->assertCount( 6, $claim->get_actions() );
$this->assertEqualSets( array_slice( $created_actions[ $unique_group_one ], 6, 6 ), $claim->get_actions() );
$store->release_claim( $claim );
$claim = $store->stake_claim( 10, null, $unique_hooks, $unique_group_two );
$this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
$this->assertCount( 6, $claim->get_actions() );
$this->assertEqualSets( array_slice( $created_actions[ $unique_group_two ], 6, 6 ), $claim->get_actions() );
$store->release_claim( $claim );
/** Test Just One Hook with Group One */
$claim = $store->stake_claim( 10, null, array( $unique_hook_one ), $unique_group_one );
$this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
$this->assertCount( 3, $claim->get_actions() );
$this->assertEqualSets( array_slice( $created_actions_by_hook[ $unique_hook_one ][ $unique_group_one ], 3, 3 ), $claim->get_actions() );
$store->release_claim( $claim );
$claim = $store->stake_claim( 24, null, array( $unique_hook_two ), $unique_group_one );
$this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
$this->assertCount( 3, $claim->get_actions() );
$this->assertEqualSets( array_slice( $created_actions_by_hook[ $unique_hook_two ][ $unique_group_one ], 3, 3 ), $claim->get_actions() );
$store->release_claim( $claim );
/** Test Just One Hook with Group Two */
$claim = $store->stake_claim( 10, null, array( $unique_hook_one ), $unique_group_two );
$this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
$this->assertCount( 3, $claim->get_actions() );
$this->assertEqualSets( array_slice( $created_actions_by_hook[ $unique_hook_one ][ $unique_group_two ], 3, 3 ), $claim->get_actions() );
$store->release_claim( $claim );
$claim = $store->stake_claim( 24, null, array( $unique_hook_two ), $unique_group_two );
$this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
$this->assertCount( 3, $claim->get_actions() );
$this->assertEqualSets( array_slice( $created_actions_by_hook[ $unique_hook_two ][ $unique_group_two ], 3, 3 ), $claim->get_actions() );
}
/**
* The query used to claim actions explicitly ignores future pending actions, but it
* is still possible under unusual conditions (such as if MySQL runs out of temporary
* storage space) for such actions to be returned.
*
* When this happens, we still expect the store to filter them out, otherwise there is
* a risk that actions will be unexpectedly processed ahead of time.
*
* @see https://github.com/woocommerce/action-scheduler/issues/634
*/
public function test_claim_filters_out_unexpected_future_actions() {
$group = __METHOD__;
$store = new ActionScheduler_DBStore();
// Create 4 actions: 2 that are already due (-3hrs and -1hrs) and 2 that are not yet due (+1hr and +3hrs).
for ( $i = -3; $i <= 3; $i += 2 ) {
$schedule = new ActionScheduler_SimpleSchedule( as_get_datetime_object( $i . ' hours' ) );
$action_ids[] = $store->save_action( new ActionScheduler_Action( 'test_' . $i, array(), $schedule, $group ) );
}
// This callback is used to simulate the unusual conditions whereby MySQL might unexpectedly return future
// actions, contrary to the conditions used by the store object when staking its claim.
$simulate_unexpected_db_behavior = function( $sql ) use ( $action_ids ) {
global $wpdb;
// Look out for the claim update query, ignore all others.
if (
0 !== strpos( $sql, "UPDATE $wpdb->actionscheduler_actions" )
|| ! preg_match( "/claim_id = 0 AND scheduled_date_gmt <= '([0-9:\-\s]{19})'/", $sql, $matches )
|| count( $matches ) !== 2
) {
return $sql;
}
// Now modify the query, forcing it to also return the future actions we created.
return str_replace( $matches[1], as_get_datetime_object( '+4 hours' )->format( 'Y-m-d H:i:s' ), $sql );
};
add_filter( 'query', $simulate_unexpected_db_behavior );
$claim = $store->stake_claim( 10, null, array(), $group );
$claimed_actions = $claim->get_actions();
$this->assertCount( 2, $claimed_actions );
// Cleanup.
remove_filter( 'query', $simulate_unexpected_db_behavior );
$store->release_claim( $claim );
}
public function test_duplicate_claim() {
$created_actions = [];
$store = new ActionScheduler_DBStore();
for ( $i = 0; $i > - 3; $i -- ) {
$time = as_get_datetime_object( $i . ' hours' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [ $i ], $schedule, 'my_group' );
$created_actions[] = $store->save_action( $action );
}
$claim1 = $store->stake_claim();
$claim2 = $store->stake_claim();
$this->assertCount( 3, $claim1->get_actions() );
$this->assertCount( 0, $claim2->get_actions() );
}
public function test_release_claim() {
$created_actions = [];
$store = new ActionScheduler_DBStore();
for ( $i = 0; $i > - 3; $i -- ) {
$time = as_get_datetime_object( $i . ' hours' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [ $i ], $schedule, 'my_group' );
$created_actions[] = $store->save_action( $action );
}
$claim1 = $store->stake_claim();
$store->release_claim( $claim1 );
$claim2 = $store->stake_claim();
$this->assertCount( 3, $claim2->get_actions() );
}
public function test_search() {
$created_actions = [];
$store = new ActionScheduler_DBStore();
for ( $i = - 3; $i <= 3; $i ++ ) {
$time = as_get_datetime_object( $i . ' hours' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [ $i ], $schedule, 'my_group' );
$created_actions[] = $store->save_action( $action );
}
$next_no_args = $store->find_action( 'my_hook' );
$this->assertEquals( $created_actions[ 0 ], $next_no_args );
$next_with_args = $store->find_action( 'my_hook', [ 'args' => [ 1 ] ] );
$this->assertEquals( $created_actions[ 4 ], $next_with_args );
$non_existent = $store->find_action( 'my_hook', [ 'args' => [ 17 ] ] );
$this->assertNull( $non_existent );
}
public function test_search_by_group() {
$store = new ActionScheduler_DBStore();
$schedule = new ActionScheduler_SimpleSchedule( as_get_datetime_object( 'tomorrow' ) );
$abc = $store->save_action( new ActionScheduler_Action( 'my_hook', [ 1 ], $schedule, 'abc' ) );
$def = $store->save_action( new ActionScheduler_Action( 'my_hook', [ 1 ], $schedule, 'def' ) );
$ghi = $store->save_action( new ActionScheduler_Action( 'my_hook', [ 1 ], $schedule, 'ghi' ) );
$this->assertEquals( $abc, $store->find_action( 'my_hook', [ 'group' => 'abc' ] ) );
$this->assertEquals( $def, $store->find_action( 'my_hook', [ 'group' => 'def' ] ) );
$this->assertEquals( $ghi, $store->find_action( 'my_hook', [ 'group' => 'ghi' ] ) );
}
public function test_get_run_date() {
$time = as_get_datetime_object( '-10 minutes' );
$schedule = new ActionScheduler_IntervalSchedule( $time, HOUR_IN_SECONDS );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule );
$store = new ActionScheduler_DBStore();
$action_id = $store->save_action( $action );
$this->assertEquals( $time->format( 'U' ), $store->get_date( $action_id )->format( 'U' ) );
$action = $store->fetch_action( $action_id );
$action->execute();
$now = as_get_datetime_object();
$store->mark_complete( $action_id );
$this->assertEquals( $now->format( 'U' ), $store->get_date( $action_id )->format( 'U' ) );
$next = $action->get_schedule()->get_next( $now );
$new_action_id = $store->save_action( $action, $next );
$this->assertEquals( (int) ( $now->format( 'U' ) ) + HOUR_IN_SECONDS, $store->get_date( $new_action_id )->format( 'U' ) );
}
public function test_get_status() {
$time = as_get_datetime_object('-10 minutes');
$schedule = new ActionScheduler_IntervalSchedule($time, HOUR_IN_SECONDS);
$action = new ActionScheduler_Action('my_hook', array(), $schedule);
$store = new ActionScheduler_DBStore();
$action_id = $store->save_action($action);
$this->assertEquals( ActionScheduler_Store::STATUS_PENDING, $store->get_status( $action_id ) );
$store->mark_complete( $action_id );
$this->assertEquals( ActionScheduler_Store::STATUS_COMPLETE, $store->get_status( $action_id ) );
$store->mark_failure( $action_id );
$this->assertEquals( ActionScheduler_Store::STATUS_FAILED, $store->get_status( $action_id ) );
}
}

View File

@ -0,0 +1,273 @@
<?php
use Action_Scheduler\Migration\Config;
use ActionScheduler_NullAction as NullAction;
use ActionScheduler_wpCommentLogger as CommentLogger;
use ActionScheduler_wpPostStore as PostStore;
/**
* Class ActionScheduler_HybridStore_Test
* @group tables
*/
class ActionScheduler_HybridStore_Test extends ActionScheduler_UnitTestCase {
private $demarkation_id = 1000;
public function setUp() {
parent::setUp();
if ( ! taxonomy_exists( PostStore::GROUP_TAXONOMY ) ) {
// register the post type and taxonomy necessary for the store to work
$store = new PostStore();
$store->init();
}
update_option( ActionScheduler_HybridStore::DEMARKATION_OPTION, $this->demarkation_id );
$hybrid = new ActionScheduler_HybridStore();
$hybrid->set_autoincrement( '', ActionScheduler_StoreSchema::ACTIONS_TABLE );
}
public function tearDown() {
parent::tearDown();
// reset the autoincrement index
/** @var \wpdb $wpdb */
global $wpdb;
$wpdb->query( "TRUNCATE TABLE {$wpdb->actionscheduler_actions}" );
$wpdb->query( "TRUNCATE TABLE {$wpdb->actionscheduler_logs}" );
delete_option( ActionScheduler_HybridStore::DEMARKATION_OPTION );
}
public function test_actions_are_migrated_on_find() {
$source_store = new PostStore();
$destination_store = new ActionScheduler_DBStore();
$source_logger = new CommentLogger();
$destination_logger = new ActionScheduler_DBLogger();
$config = new Config();
$config->set_source_store( $source_store );
$config->set_source_logger( $source_logger );
$config->set_destination_store( $destination_store );
$config->set_destination_logger( $destination_logger );
$hybrid_store = new ActionScheduler_HybridStore( $config );
$time = as_get_datetime_object( '10 minutes ago' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
$source_id = $source_store->save_action( $action );
$found = $hybrid_store->find_action( __FUNCTION__, [] );
$this->assertNotEquals( $source_id, $found );
$this->assertGreaterThanOrEqual( $this->demarkation_id, $found );
$found_in_source = $source_store->fetch_action( $source_id );
$this->assertInstanceOf( NullAction::class, $found_in_source );
}
public function test_actions_are_migrated_on_query() {
$source_store = new PostStore();
$destination_store = new ActionScheduler_DBStore();
$source_logger = new CommentLogger();
$destination_logger = new ActionScheduler_DBLogger();
$config = new Config();
$config->set_source_store( $source_store );
$config->set_source_logger( $source_logger );
$config->set_destination_store( $destination_store );
$config->set_destination_logger( $destination_logger );
$hybrid_store = new ActionScheduler_HybridStore( $config );
$source_actions = [];
$destination_actions = [];
for ( $i = 0; $i < 10; $i++ ) {
// create in instance in the source store
$time = as_get_datetime_object( ( $i * 10 + 1 ) . ' minutes' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
$source_actions[] = $source_store->save_action( $action );
// create an instance in the destination store
$time = as_get_datetime_object( ( $i * 10 + 5 ) . ' minutes' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
$destination_actions[] = $destination_store->save_action( $action );
}
$found = $hybrid_store->query_actions([
'hook' => __FUNCTION__,
'per_page' => 6,
] );
$this->assertCount( 6, $found );
foreach ( $found as $key => $action_id ) {
$this->assertNotContains( $action_id, $source_actions );
$this->assertGreaterThanOrEqual( $this->demarkation_id, $action_id );
if ( $key % 2 == 0 ) { // it should have been in the source store
$this->assertNotContains( $action_id, $destination_actions );
} else { // it should have already been in the destination store
$this->assertContains( $action_id, $destination_actions );
}
}
// six of the original 10 should have migrated to the new store
// even though only three were retrieve in the final query
$found_in_source = $source_store->query_actions( [
'hook' => __FUNCTION__,
'per_page' => 10,
] );
$this->assertCount( 4, $found_in_source );
}
public function test_actions_are_migrated_on_claim() {
$source_store = new PostStore();
$destination_store = new ActionScheduler_DBStore();
$source_logger = new CommentLogger();
$destination_logger = new ActionScheduler_DBLogger();
$config = new Config();
$config->set_source_store( $source_store );
$config->set_source_logger( $source_logger );
$config->set_destination_store( $destination_store );
$config->set_destination_logger( $destination_logger );
$hybrid_store = new ActionScheduler_HybridStore( $config );
$source_actions = [];
$destination_actions = [];
for ( $i = 0; $i < 10; $i++ ) {
// create in instance in the source store
$time = as_get_datetime_object( ( $i * 10 + 1 ) . ' minutes ago' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
$source_actions[] = $source_store->save_action( $action );
// create an instance in the destination store
$time = as_get_datetime_object( ( $i * 10 + 5 ) . ' minutes ago' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
$destination_actions[] = $destination_store->save_action( $action );
}
$claim = $hybrid_store->stake_claim( 6 );
$claimed_actions = $claim->get_actions();
$this->assertCount( 6, $claimed_actions );
$this->assertCount( 3, array_intersect( $destination_actions, $claimed_actions ) );
// six of the original 10 should have migrated to the new store
// even though only three were retrieve in the final claim
$found_in_source = $source_store->query_actions( [
'hook' => __FUNCTION__,
'per_page' => 10,
] );
$this->assertCount( 4, $found_in_source );
$this->assertEquals( 0, $source_store->get_claim_count() );
$this->assertEquals( 1, $destination_store->get_claim_count() );
$this->assertEquals( 1, $hybrid_store->get_claim_count() );
}
public function test_fetch_respects_demarkation() {
$source_store = new PostStore();
$destination_store = new ActionScheduler_DBStore();
$source_logger = new CommentLogger();
$destination_logger = new ActionScheduler_DBLogger();
$config = new Config();
$config->set_source_store( $source_store );
$config->set_source_logger( $source_logger );
$config->set_destination_store( $destination_store );
$config->set_destination_logger( $destination_logger );
$hybrid_store = new ActionScheduler_HybridStore( $config );
$source_actions = [];
$destination_actions = [];
for ( $i = 0; $i < 2; $i++ ) {
// create in instance in the source store
$time = as_get_datetime_object( ( $i * 10 + 1 ) . ' minutes ago' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
$source_actions[] = $source_store->save_action( $action );
// create an instance in the destination store
$time = as_get_datetime_object( ( $i * 10 + 5 ) . ' minutes ago' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
$destination_actions[] = $destination_store->save_action( $action );
}
foreach ( $source_actions as $action_id ) {
$action = $hybrid_store->fetch_action( $action_id );
$this->assertInstanceOf( ActionScheduler_Action::class, $action );
$this->assertNotInstanceOf( NullAction::class, $action );
}
foreach ( $destination_actions as $action_id ) {
$action = $hybrid_store->fetch_action( $action_id );
$this->assertInstanceOf( ActionScheduler_Action::class, $action );
$this->assertNotInstanceOf( NullAction::class, $action );
}
}
public function test_mark_complete_respects_demarkation() {
$source_store = new PostStore();
$destination_store = new ActionScheduler_DBStore();
$source_logger = new CommentLogger();
$destination_logger = new ActionScheduler_DBLogger();
$config = new Config();
$config->set_source_store( $source_store );
$config->set_source_logger( $source_logger );
$config->set_destination_store( $destination_store );
$config->set_destination_logger( $destination_logger );
$hybrid_store = new ActionScheduler_HybridStore( $config );
$source_actions = [];
$destination_actions = [];
for ( $i = 0; $i < 2; $i++ ) {
// create in instance in the source store
$time = as_get_datetime_object( ( $i * 10 + 1 ) . ' minutes ago' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
$source_actions[] = $source_store->save_action( $action );
// create an instance in the destination store
$time = as_get_datetime_object( ( $i * 10 + 5 ) . ' minutes ago' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
$destination_actions[] = $destination_store->save_action( $action );
}
foreach ( $source_actions as $action_id ) {
$hybrid_store->mark_complete( $action_id );
$action = $hybrid_store->fetch_action( $action_id );
$this->assertInstanceOf( ActionScheduler_FinishedAction::class, $action );
}
foreach ( $destination_actions as $action_id ) {
$hybrid_store->mark_complete( $action_id );
$action = $hybrid_store->fetch_action( $action_id );
$this->assertInstanceOf( ActionScheduler_FinishedAction::class, $action );
}
}
}

View File

@ -0,0 +1,466 @@
<?php
/**
* Class ActionScheduler_wpPostStore_Test
* @group stores
*/
class ActionScheduler_wpPostStore_Test extends ActionScheduler_UnitTestCase {
public function test_create_action() {
$time = as_get_datetime_object();
$schedule = new ActionScheduler_SimpleSchedule($time);
$action = new ActionScheduler_Action('my_hook', array(), $schedule);
$store = new ActionScheduler_wpPostStore();
$action_id = $store->save_action($action);
$this->assertNotEmpty($action_id);
}
public function test_create_action_with_scheduled_date() {
$time = as_get_datetime_object( strtotime( '-1 week' ) );
$action = new ActionScheduler_Action( 'my_hook', array(), new ActionScheduler_SimpleSchedule( $time ) );
$store = new ActionScheduler_wpPostStore();
$action_id = $store->save_action( $action, $time );
$action_date = $store->get_date( $action_id );
$this->assertEquals( $time->getTimestamp(), $action_date->getTimestamp() );
}
public function test_retrieve_action() {
$time = as_get_datetime_object();
$schedule = new ActionScheduler_SimpleSchedule($time);
$action = new ActionScheduler_Action('my_hook', array(), $schedule, 'my_group');
$store = new ActionScheduler_wpPostStore();
$action_id = $store->save_action($action);
$retrieved = $store->fetch_action($action_id);
$this->assertEquals($action->get_hook(), $retrieved->get_hook());
$this->assertEqualSets($action->get_args(), $retrieved->get_args());
$this->assertEquals( $action->get_schedule()->get_date()->getTimestamp(), $retrieved->get_schedule()->get_date()->getTimestamp() );
$this->assertEquals($action->get_group(), $retrieved->get_group());
}
/**
* @dataProvider provide_bad_args
*
* @param string $content
*/
public function test_action_bad_args( $content ) {
$store = new ActionScheduler_wpPostStore();
$post_id = wp_insert_post( array(
'post_type' => ActionScheduler_wpPostStore::POST_TYPE,
'post_status' => ActionScheduler_Store::STATUS_PENDING,
'post_content' => $content,
) );
$fetched = $store->fetch_action( $post_id );
$this->assertInstanceOf( 'ActionScheduler_NullSchedule', $fetched->get_schedule() );
}
public function provide_bad_args() {
return array(
array( '{"bad_json":true}}' ),
);
}
public function test_cancel_action() {
$time = as_get_datetime_object();
$schedule = new ActionScheduler_SimpleSchedule($time);
$action = new ActionScheduler_Action('my_hook', array(), $schedule, 'my_group');
$store = new ActionScheduler_wpPostStore();
$action_id = $store->save_action($action);
$store->cancel_action( $action_id );
$fetched = $store->fetch_action( $action_id );
$this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
}
public function test_cancel_actions_by_hook() {
$store = new ActionScheduler_wpPostStore();
$actions = array();
$hook = 'by_hook_test';
for ( $day = 1; $day <= 3; $day++ ) {
$delta = sprintf( '+%d day', $day );
$time = as_get_datetime_object( $delta );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( $hook, array(), $schedule, 'my_group' );
$actions[] = $store->save_action( $action );
}
$store->cancel_actions_by_hook( $hook );
foreach ( $actions as $action_id ) {
$fetched = $store->fetch_action( $action_id );
$this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
}
}
public function test_cancel_actions_by_group() {
$store = new ActionScheduler_wpPostStore();
$actions = array();
$group = 'by_group_test';
for ( $day = 1; $day <= 3; $day++ ) {
$delta = sprintf( '+%d day', $day );
$time = as_get_datetime_object( $delta );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', array(), $schedule, $group );
$actions[] = $store->save_action( $action );
}
$store->cancel_actions_by_group( $group );
foreach ( $actions as $action_id ) {
$fetched = $store->fetch_action( $action_id );
$this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
}
}
public function test_claim_actions() {
$created_actions = array();
$store = new ActionScheduler_wpPostStore();
for ( $i = 3 ; $i > -3 ; $i-- ) {
$time = as_get_datetime_object($i.' hours');
$schedule = new ActionScheduler_SimpleSchedule($time);
$action = new ActionScheduler_Action('my_hook', array($i), $schedule, 'my_group');
$created_actions[] = $store->save_action($action);
}
$claim = $store->stake_claim();
$this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
$this->assertCount( 3, $claim->get_actions() );
$this->assertEqualSets( array_slice( $created_actions, 3, 3 ), $claim->get_actions() );
}
public function test_claim_actions_order() {
$store = new ActionScheduler_wpPostStore();
$schedule = new ActionScheduler_SimpleSchedule( as_get_datetime_object( '-1 hour' ) );
$created_actions = array(
$store->save_action( new ActionScheduler_Action( 'my_hook', array( 1 ), $schedule, 'my_group' ) ),
$store->save_action( new ActionScheduler_Action( 'my_hook', array( 1 ), $schedule, 'my_group' ) ),
);
$claim = $store->stake_claim();
$this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
// Verify uniqueness of action IDs.
$this->assertEquals( 2, count( array_unique( $created_actions ) ) );
// Verify the count and order of the actions.
$claimed_actions = $claim->get_actions();
$this->assertCount( 2, $claimed_actions );
$this->assertEquals( $created_actions, $claimed_actions );
// Verify the reversed order doesn't pass.
$reversed_actions = array_reverse( $created_actions );
$this->assertNotEquals( $reversed_actions, $claimed_actions );
}
public function test_duplicate_claim() {
$created_actions = array();
$store = new ActionScheduler_wpPostStore();
for ( $i = 0 ; $i > -3 ; $i-- ) {
$time = as_get_datetime_object($i.' hours');
$schedule = new ActionScheduler_SimpleSchedule($time);
$action = new ActionScheduler_Action('my_hook', array($i), $schedule, 'my_group');
$created_actions[] = $store->save_action($action);
}
$claim1 = $store->stake_claim();
$claim2 = $store->stake_claim();
$this->assertCount( 3, $claim1->get_actions() );
$this->assertCount( 0, $claim2->get_actions() );
}
public function test_release_claim() {
$created_actions = array();
$store = new ActionScheduler_wpPostStore();
for ( $i = 0 ; $i > -3 ; $i-- ) {
$time = as_get_datetime_object($i.' hours');
$schedule = new ActionScheduler_SimpleSchedule($time);
$action = new ActionScheduler_Action('my_hook', array($i), $schedule, 'my_group');
$created_actions[] = $store->save_action($action);
}
$claim1 = $store->stake_claim();
$store->release_claim( $claim1 );
$claim2 = $store->stake_claim();
$this->assertCount( 3, $claim2->get_actions() );
}
public function test_search() {
$created_actions = array();
$store = new ActionScheduler_wpPostStore();
for ( $i = -3 ; $i <= 3 ; $i++ ) {
$time = as_get_datetime_object($i.' hours');
$schedule = new ActionScheduler_SimpleSchedule($time);
$action = new ActionScheduler_Action('my_hook', array($i), $schedule, 'my_group');
$created_actions[] = $store->save_action($action);
}
$next_no_args = $store->find_action( 'my_hook' );
$this->assertEquals( $created_actions[0], $next_no_args );
$next_with_args = $store->find_action( 'my_hook', array( 'args' => array( 1 ) ) );
$this->assertEquals( $created_actions[4], $next_with_args );
$non_existent = $store->find_action( 'my_hook', array( 'args' => array( 17 ) ) );
$this->assertNull( $non_existent );
}
public function test_search_by_group() {
$store = new ActionScheduler_wpPostStore();
$schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('tomorrow'));
$abc = $store->save_action(new ActionScheduler_Action('my_hook', array(1), $schedule, 'abc'));
$def = $store->save_action(new ActionScheduler_Action('my_hook', array(1), $schedule, 'def'));
$ghi = $store->save_action(new ActionScheduler_Action('my_hook', array(1), $schedule, 'ghi'));
$this->assertEquals( $abc, $store->find_action('my_hook', array('group' => 'abc')));
$this->assertEquals( $def, $store->find_action('my_hook', array('group' => 'def')));
$this->assertEquals( $ghi, $store->find_action('my_hook', array('group' => 'ghi')));
}
public function test_post_author() {
$current_user = get_current_user_id();
$time = as_get_datetime_object();
$schedule = new ActionScheduler_SimpleSchedule($time);
$action = new ActionScheduler_Action('my_hook', array(), $schedule);
$store = new ActionScheduler_wpPostStore();
$action_id = $store->save_action($action);
$post = get_post($action_id);
$this->assertEquals(0, $post->post_author);
$new_user = $this->factory->user->create_object(array(
'user_login' => __FUNCTION__,
'user_pass' => md5(rand()),
));
wp_set_current_user( $new_user );
$schedule = new ActionScheduler_SimpleSchedule($time);
$action = new ActionScheduler_Action('my_hook', array(), $schedule);
$action_id = $store->save_action($action);
$post = get_post($action_id);
$this->assertEquals(0, $post->post_author);
wp_set_current_user($current_user);
}
/**
* @issue 13
*/
public function test_post_status_for_recurring_action() {
$time = as_get_datetime_object('10 minutes');
$schedule = new ActionScheduler_IntervalSchedule($time, HOUR_IN_SECONDS);
$action = new ActionScheduler_Action('my_hook', array(), $schedule);
$store = new ActionScheduler_wpPostStore();
$action_id = $store->save_action($action);
$action = $store->fetch_action($action_id);
$action->execute();
$store->mark_complete( $action_id );
$next = $action->get_schedule()->get_next( as_get_datetime_object() );
$new_action_id = $store->save_action( $action, $next );
$this->assertEquals('publish', get_post_status($action_id));
$this->assertEquals('pending', get_post_status($new_action_id));
}
public function test_get_run_date() {
$time = as_get_datetime_object('-10 minutes');
$schedule = new ActionScheduler_IntervalSchedule($time, HOUR_IN_SECONDS);
$action = new ActionScheduler_Action('my_hook', array(), $schedule);
$store = new ActionScheduler_wpPostStore();
$action_id = $store->save_action($action);
$this->assertEquals( $store->get_date($action_id)->getTimestamp(), $time->getTimestamp() );
$action = $store->fetch_action($action_id);
$action->execute();
$now = as_get_datetime_object();
$store->mark_complete( $action_id );
$this->assertEquals( $store->get_date( $action_id )->getTimestamp(), $now->getTimestamp(), '', 1 ); // allow timestamp to be 1 second off for older versions of PHP
$next = $action->get_schedule()->get_next( $now );
$new_action_id = $store->save_action( $action, $next );
$this->assertEquals( (int)($now->getTimestamp()) + HOUR_IN_SECONDS, $store->get_date($new_action_id)->getTimestamp() );
}
public function test_get_status() {
$time = as_get_datetime_object('-10 minutes');
$schedule = new ActionScheduler_IntervalSchedule($time, HOUR_IN_SECONDS);
$action = new ActionScheduler_Action('my_hook', array(), $schedule);
$store = new ActionScheduler_wpPostStore();
$action_id = $store->save_action($action);
$this->assertEquals( ActionScheduler_Store::STATUS_PENDING, $store->get_status( $action_id ) );
$store->mark_complete( $action_id );
$this->assertEquals( ActionScheduler_Store::STATUS_COMPLETE, $store->get_status( $action_id ) );
$store->mark_failure( $action_id );
$this->assertEquals( ActionScheduler_Store::STATUS_FAILED, $store->get_status( $action_id ) );
}
public function test_claim_actions_by_hooks() {
$hook1 = __FUNCTION__ . '_hook_1';
$hook2 = __FUNCTION__ . '_hook_2';
$store = new ActionScheduler_wpPostStore();
$schedule = new ActionScheduler_SimpleSchedule( as_get_datetime_object( '-1 hour' ) );
$action1 = $store->save_action( new ActionScheduler_Action( $hook1, array(), $schedule ) );
$action2 = $store->save_action( new ActionScheduler_Action( $hook2, array(), $schedule ) );
// Claiming no hooks should include all actions.
$claim = $store->stake_claim( 10 );
$this->assertEquals( 2, count( $claim->get_actions() ) );
$this->assertTrue( in_array( $action1, $claim->get_actions() ) );
$this->assertTrue( in_array( $action2, $claim->get_actions() ) );
$store->release_claim( $claim );
// Claiming a hook should claim only actions with that hook
$claim = $store->stake_claim( 10, null, array( $hook1 ) );
$this->assertEquals( 1, count( $claim->get_actions() ) );
$this->assertTrue( in_array( $action1, $claim->get_actions() ) );
$store->release_claim( $claim );
// Claiming two hooks should claim actions with either of those hooks
$claim = $store->stake_claim( 10, null, array( $hook1, $hook2 ) );
$this->assertEquals( 2, count( $claim->get_actions() ) );
$this->assertTrue( in_array( $action1, $claim->get_actions() ) );
$this->assertTrue( in_array( $action2, $claim->get_actions() ) );
$store->release_claim( $claim );
// Claiming two hooks should claim actions with either of those hooks
$claim = $store->stake_claim( 10, null, array( __METHOD__ . '_hook_3' ) );
$this->assertEquals( 0, count( $claim->get_actions() ) );
$this->assertFalse( in_array( $action1, $claim->get_actions() ) );
$this->assertFalse( in_array( $action2, $claim->get_actions() ) );
$store->release_claim( $claim );
}
/**
* @issue 121
*/
public function test_claim_actions_by_group() {
$group1 = md5( rand() );
$store = new ActionScheduler_wpPostStore();
$schedule = new ActionScheduler_SimpleSchedule( as_get_datetime_object( '-1 hour' ) );
$action1 = $store->save_action( new ActionScheduler_Action( __METHOD__, array(), $schedule, $group1 ) );
$action2 = $store->save_action( new ActionScheduler_Action( __METHOD__, array(), $schedule ) );
// Claiming no group should include all actions.
$claim = $store->stake_claim( 10 );
$this->assertEquals( 2, count( $claim->get_actions() ) );
$this->assertTrue( in_array( $action1, $claim->get_actions() ) );
$this->assertTrue( in_array( $action2, $claim->get_actions() ) );
$store->release_claim( $claim );
// Claiming a group should claim only actions in that group.
$claim = $store->stake_claim( 10, null, array(), $group1 );
$this->assertEquals( 1, count( $claim->get_actions() ) );
$this->assertTrue( in_array( $action1, $claim->get_actions() ) );
$store->release_claim( $claim );
}
public function test_claim_actions_by_hook_and_group() {
$hook1 = __FUNCTION__ . '_hook_1';
$hook2 = __FUNCTION__ . '_hook_2';
$hook3 = __FUNCTION__ . '_hook_3';
$group1 = 'group_' . md5( rand() );
$group2 = 'group_' . md5( rand() );
$store = new ActionScheduler_wpPostStore();
$schedule = new ActionScheduler_SimpleSchedule( as_get_datetime_object( '-1 hour' ) );
$action1 = $store->save_action( new ActionScheduler_Action( $hook1, array(), $schedule, $group1 ) );
$action2 = $store->save_action( new ActionScheduler_Action( $hook2, array(), $schedule ) );
$action3 = $store->save_action( new ActionScheduler_Action( $hook3, array(), $schedule, $group2 ) );
// Claiming no hooks or group should include all actions.
$claim = $store->stake_claim( 10 );
$this->assertEquals( 3, count( $claim->get_actions() ) );
$this->assertTrue( in_array( $action1, $claim->get_actions() ) );
$this->assertTrue( in_array( $action2, $claim->get_actions() ) );
$store->release_claim( $claim );
// Claiming a group and hook should claim only actions in that group.
$claim = $store->stake_claim( 10, null, array( $hook1 ), $group1 );
$this->assertEquals( 1, count( $claim->get_actions() ) );
$this->assertTrue( in_array( $action1, $claim->get_actions() ) );
$store->release_claim( $claim );
// Claiming a group and hook should claim only actions with that hook in that group.
$claim = $store->stake_claim( 10, null, array( $hook2 ), $group1 );
$this->assertEquals( 0, count( $claim->get_actions() ) );
$this->assertFalse( in_array( $action1, $claim->get_actions() ) );
$this->assertFalse( in_array( $action2, $claim->get_actions() ) );
$store->release_claim( $claim );
// Claiming a group and hook should claim only actions with that hook in that group.
$claim = $store->stake_claim( 10, null, array( $hook1, $hook2 ), $group2 );
$this->assertEquals( 0, count( $claim->get_actions() ) );
$this->assertFalse( in_array( $action1, $claim->get_actions() ) );
$this->assertFalse( in_array( $action2, $claim->get_actions() ) );
$store->release_claim( $claim );
}
/**
* The query used to claim actions explicitly ignores future pending actions, but it
* is still possible under unusual conditions (such as if MySQL runs out of temporary
* storage space) for such actions to be returned.
*
* When this happens, we still expect the store to filter them out, otherwise there is
* a risk that actions will be unexpectedly processed ahead of time.
*
* @see https://github.com/woocommerce/action-scheduler/issues/634
*/
public function test_claim_filters_out_unexpected_future_actions() {
$group = __METHOD__;
$store = new ActionScheduler_wpPostStore();
// Create 4 actions: 2 that are already due (-3hrs and -1hrs) and 2 that are not yet due (+1hr and +3hrs).
for ( $i = -3; $i <= 3; $i += 2 ) {
$schedule = new ActionScheduler_SimpleSchedule( as_get_datetime_object( $i . ' hours' ) );
$action_ids[] = $store->save_action( new ActionScheduler_Action( 'test_' . $i, array(), $schedule, $group ) );
}
// This callback is used to simulate the unusual conditions whereby MySQL might unexpectedly return future
// actions, contrary to the conditions used by the store object when staking its claim.
$simulate_unexpected_db_behavior = function( $sql ) use ( $action_ids ) {
global $wpdb;
$post_type = ActionScheduler_wpPostStore::POST_TYPE;
$pending = ActionScheduler_wpPostStore::STATUS_PENDING;
// Look out for the claim update query, ignore all others.
if (
0 !== strpos( $sql, "UPDATE $wpdb->posts" )
|| 0 !== strpos( $sql, "WHERE post_type = '$post_type' AND post_status = '$pending' AND post_password = ''" )
|| ! preg_match( "/AND post_date_gmt <= '([0-9:\-\s]{19})'/", $sql, $matches )
|| count( $matches ) !== 2
) {
return $sql;
}
// Now modify the query, forcing it to also return the future actions we created.
return str_replace( $matches[1], as_get_datetime_object( '+4 hours' )->format( 'Y-m-d H:i:s' ), $sql );
};
add_filter( 'query', $simulate_unexpected_db_behavior );
$claim = $store->stake_claim( 10, null, array(), $group );
$claimed_actions = $claim->get_actions();
$this->assertCount( 2, $claimed_actions );
// Cleanup.
remove_filter( 'query', $simulate_unexpected_db_behavior );
$store->release_claim( $claim );
}
}

View File

@ -0,0 +1,45 @@
<?php
/**
* Class ActionScheduler_Lock_Test
* @package test_cases\lock
*/
class ActionScheduler_OptionLock_Test extends ActionScheduler_UnitTestCase {
public function test_instance() {
$lock = ActionScheduler::lock();
$this->assertInstanceOf( 'ActionScheduler_Lock', $lock );
$this->assertInstanceOf( 'ActionScheduler_OptionLock', $lock );
}
public function test_is_locked() {
$lock = ActionScheduler::lock();
$lock_type = md5( rand() );
$this->assertFalse( $lock->is_locked( $lock_type ) );
$lock->set( $lock_type );
$this->assertTrue( $lock->is_locked( $lock_type ) );
}
public function test_set() {
$lock = ActionScheduler::lock();
$lock_type = md5( rand() );
$lock->set( $lock_type );
$this->assertTrue( $lock->is_locked( $lock_type ) );
}
public function test_get_expiration() {
$lock = ActionScheduler::lock();
$lock_type = md5( rand() );
$lock->set( $lock_type );
$expiration = $lock->get_expiration( $lock_type );
$current_time = time();
$this->assertGreaterThanOrEqual( 0, $expiration );
$this->assertGreaterThan( $current_time, $expiration );
$this->assertLessThan( $current_time + MINUTE_IN_SECONDS + 1, $expiration );
}
}

View File

@ -0,0 +1,132 @@
<?php
/**
* Class ActionScheduler_DBLogger_Test
* @package test_cases\logging
* @group tables
*/
class ActionScheduler_DBLogger_Test extends ActionScheduler_UnitTestCase {
public function test_default_logger() {
$logger = ActionScheduler::logger();
$this->assertInstanceOf( 'ActionScheduler_Logger', $logger );
$this->assertInstanceOf( ActionScheduler_DBLogger::class, $logger );
}
public function test_add_log_entry() {
$action_id = as_schedule_single_action( time(), __METHOD__ );
$logger = ActionScheduler::logger();
$message = 'Logging that something happened';
$log_id = $logger->log( $action_id, $message );
$entry = $logger->get_entry( $log_id );
$this->assertEquals( $action_id, $entry->get_action_id() );
$this->assertEquals( $message, $entry->get_message() );
}
public function test_storage_logs() {
$action_id = as_schedule_single_action( time(), __METHOD__ );
$logger = ActionScheduler::logger();
$logs = $logger->get_logs( $action_id );
$expected = new ActionScheduler_LogEntry( $action_id, 'action created' );
$this->assertCount( 1, $logs );
$this->assertEquals( $expected->get_action_id(), $logs[0]->get_action_id() );
$this->assertEquals( $expected->get_message(), $logs[0]->get_message() );
}
public function test_execution_logs() {
$action_id = as_schedule_single_action( time(), __METHOD__ );
$logger = ActionScheduler::logger();
$started = new ActionScheduler_LogEntry( $action_id, 'action started via Unit Tests' );
$finished = new ActionScheduler_LogEntry( $action_id, 'action complete via Unit Tests' );
$runner = ActionScheduler_Mocker::get_queue_runner();
$runner->run( 'Unit Tests' );
// Expect 3 logs with the correct action ID.
$logs = $logger->get_logs( $action_id );
$this->assertCount( 3, $logs );
foreach ( $logs as $log ) {
$this->assertEquals( $action_id, $log->get_action_id() );
}
// Expect created, then started, then completed.
$this->assertEquals( 'action created', $logs[0]->get_message() );
$this->assertEquals( $started->get_message(), $logs[1]->get_message() );
$this->assertEquals( $finished->get_message(), $logs[2]->get_message() );
}
public function test_failed_execution_logs() {
$hook = __METHOD__;
add_action( $hook, array( $this, '_a_hook_callback_that_throws_an_exception' ) );
$action_id = as_schedule_single_action( time(), $hook );
$logger = ActionScheduler::logger();
$started = new ActionScheduler_LogEntry( $action_id, 'action started via Unit Tests' );
$finished = new ActionScheduler_LogEntry( $action_id, 'action complete via Unit Tests' );
$failed = new ActionScheduler_LogEntry( $action_id, 'action failed via Unit Tests: Execution failed' );
$runner = ActionScheduler_Mocker::get_queue_runner();
$runner->run( 'Unit Tests' );
// Expect 3 logs with the correct action ID.
$logs = $logger->get_logs( $action_id );
$this->assertCount( 3, $logs );
foreach ( $logs as $log ) {
$this->assertEquals( $action_id, $log->get_action_id() );
$this->assertNotEquals( $finished->get_message(), $log->get_message() );
}
// Expect created, then started, then failed.
$this->assertEquals( 'action created', $logs[0]->get_message() );
$this->assertEquals( $started->get_message(), $logs[1]->get_message() );
$this->assertEquals( $failed->get_message(), $logs[2]->get_message() );
}
public function test_fatal_error_log() {
$action_id = as_schedule_single_action( time(), __METHOD__ );
$logger = ActionScheduler::logger();
do_action( 'action_scheduler_unexpected_shutdown', $action_id, array(
'type' => E_ERROR,
'message' => 'Test error',
'file' => __FILE__,
'line' => __LINE__,
));
$logs = $logger->get_logs( $action_id );
$found_log = FALSE;
foreach ( $logs as $l ) {
if ( strpos( $l->get_message(), 'unexpected shutdown' ) === 0 ) {
$found_log = TRUE;
}
}
$this->assertTrue( $found_log, 'Unexpected shutdown log not found' );
}
public function test_canceled_action_log() {
$action_id = as_schedule_single_action( time(), __METHOD__ );
as_unschedule_action( __METHOD__ );
$logger = ActionScheduler::logger();
$logs = $logger->get_logs( $action_id );
$expected = new ActionScheduler_LogEntry( $action_id, 'action canceled' );
$this->assertEquals( $expected->get_message(), end( $logs )->get_message() );
}
public function test_deleted_action_cleanup() {
$time = as_get_datetime_object('-10 minutes');
$schedule = new \ActionScheduler_SimpleSchedule($time);
$action = new \ActionScheduler_Action('my_hook', array(), $schedule);
$store = new ActionScheduler_DBStore();
$action_id = $store->save_action($action);
$logger = new ActionScheduler_DBLogger();
$logs = $logger->get_logs( $action_id );
$this->assertNotEmpty( $logs );
$store->delete_action( $action_id );
$logs = $logger->get_logs( $action_id );
$this->assertEmpty( $logs );
}
public function _a_hook_callback_that_throws_an_exception() {
throw new \RuntimeException('Execution failed');
}
}

View File

@ -0,0 +1,212 @@
<?php
/**
* Class ActionScheduler_wpCommentLogger_Test
* @package test_cases\logging
*/
class ActionScheduler_wpCommentLogger_Test extends ActionScheduler_UnitTestCase {
private $use_comment_logger;
public function test_default_logger() {
$logger = ActionScheduler::logger();
$this->assertInstanceOf( 'ActionScheduler_Logger', $logger );
if ( $this->using_comment_logger() ) {
$this->assertInstanceOf( 'ActionScheduler_wpCommentLogger', $logger );
} else {
$this->assertNotInstanceOf( 'ActionScheduler_wpCommentLogger', $logger );
}
}
public function test_add_log_entry() {
$action_id = as_schedule_single_action( time(), 'a hook' );
$logger = ActionScheduler::logger();
$message = 'Logging that something happened';
$log_id = $logger->log( $action_id, $message );
$entry = $logger->get_entry( $log_id );
$this->assertEquals( $action_id, $entry->get_action_id() );
$this->assertEquals( $message, $entry->get_message() );
}
public function test_add_log_datetime() {
$action_id = as_schedule_single_action( time(), 'a hook' );
$logger = ActionScheduler::logger();
$message = 'Logging that something happened';
$date = new DateTime( 'now', new DateTimeZone( 'UTC' ) );
$log_id = $logger->log( $action_id, $message, $date );
$entry = $logger->get_entry( $log_id );
$this->assertEquals( $action_id, $entry->get_action_id() );
$this->assertEquals( $message, $entry->get_message() );
$date = new ActionScheduler_DateTime( 'now', new DateTimeZone( 'UTC' ) );
$log_id = $logger->log( $action_id, $message, $date );
$entry = $logger->get_entry( $log_id );
$this->assertEquals( $action_id, $entry->get_action_id() );
$this->assertEquals( $message, $entry->get_message() );
}
public function test_erroneous_entry_id() {
$comment = wp_insert_comment(array(
'comment_post_ID' => 1,
'comment_author' => 'test',
'comment_content' => 'this is not a log entry',
));
$logger = ActionScheduler::logger();
$entry = $logger->get_entry( $comment );
$this->assertEquals( '', $entry->get_action_id() );
$this->assertEquals( '', $entry->get_message() );
}
public function test_storage_comments() {
$action_id = as_schedule_single_action( time(), 'a hook' );
$logger = ActionScheduler::logger();
$logs = $logger->get_logs( $action_id );
$expected = new ActionScheduler_LogEntry( $action_id, 'action created' );
$this->assertTrue( in_array( $this->log_entry_to_array( $expected ) , $this->log_entry_to_array( $logs ) ) );
}
protected function log_entry_to_array( $logs ) {
if ( $logs instanceof ActionScheduler_LogEntry ) {
return array( 'action_id' => $logs->get_action_id(), 'message' => $logs->get_message() );
}
foreach ( $logs as $id => $log) {
$logs[ $id ] = array( 'action_id' => $log->get_action_id(), 'message' => $log->get_message() );
}
return $logs;
}
public function test_execution_comments() {
$action_id = as_schedule_single_action( time(), 'a hook' );
$logger = ActionScheduler::logger();
$started = new ActionScheduler_LogEntry( $action_id, 'action started via Unit Tests' );
$finished = new ActionScheduler_LogEntry( $action_id, 'action complete via Unit Tests' );
$runner = ActionScheduler_Mocker::get_queue_runner();
$runner->run( 'Unit Tests' );
$logs = $logger->get_logs( $action_id );
$this->assertTrue( in_array( $this->log_entry_to_array( $started ), $this->log_entry_to_array( $logs ) ) );
$this->assertTrue( in_array( $this->log_entry_to_array( $finished ), $this->log_entry_to_array( $logs ) ) );
}
public function test_failed_execution_comments() {
$hook = md5(rand());
add_action( $hook, array( $this, '_a_hook_callback_that_throws_an_exception' ) );
$action_id = as_schedule_single_action( time(), $hook );
$logger = ActionScheduler::logger();
$started = new ActionScheduler_LogEntry( $action_id, 'action started via Unit Tests' );
$finished = new ActionScheduler_LogEntry( $action_id, 'action complete via Unit Tests' );
$failed = new ActionScheduler_LogEntry( $action_id, 'action failed via Unit Tests: Execution failed' );
$runner = ActionScheduler_Mocker::get_queue_runner();
$runner->run( 'Unit Tests' );
$logs = $logger->get_logs( $action_id );
$this->assertTrue( in_array( $this->log_entry_to_array( $started ), $this->log_entry_to_array( $logs ) ) );
$this->assertFalse( in_array( $this->log_entry_to_array( $finished ), $this->log_entry_to_array( $logs ) ) );
$this->assertTrue( in_array( $this->log_entry_to_array( $failed ), $this->log_entry_to_array( $logs ) ) );
}
public function test_failed_schedule_next_instance_comments() {
$action_id = rand();
$logger = ActionScheduler::logger();
$log_entry = new ActionScheduler_LogEntry( $action_id, 'There was a failure scheduling the next instance of this action: Execution failed' );
try {
$this->_a_hook_callback_that_throws_an_exception();
} catch ( Exception $e ) {
do_action( 'action_scheduler_failed_to_schedule_next_instance', $action_id, $e, new ActionScheduler_Action('my_hook') );
}
$logs = $logger->get_logs( $action_id );
$this->assertTrue( in_array( $this->log_entry_to_array( $log_entry ), $this->log_entry_to_array( $logs ) ) );
}
public function test_fatal_error_comments() {
$hook = md5(rand());
$action_id = as_schedule_single_action( time(), $hook );
$logger = ActionScheduler::logger();
do_action( 'action_scheduler_unexpected_shutdown', $action_id, array(
'type' => E_ERROR,
'message' => 'Test error',
'file' => __FILE__,
'line' => __LINE__,
));
$logs = $logger->get_logs( $action_id );
$found_log = FALSE;
foreach ( $logs as $l ) {
if ( strpos( $l->get_message(), 'unexpected shutdown' ) === 0 ) {
$found_log = TRUE;
}
}
$this->assertTrue( $found_log, 'Unexpected shutdown log not found' );
}
public function test_canceled_action_comments() {
$action_id = as_schedule_single_action( time(), 'a hook' );
as_unschedule_action( 'a hook' );
$logger = ActionScheduler::logger();
$logs = $logger->get_logs( $action_id );
$expected = new ActionScheduler_LogEntry( $action_id, 'action canceled' );
$this->assertTrue( in_array( $this->log_entry_to_array( $expected ), $this->log_entry_to_array( $logs ) ) );
}
public function _a_hook_callback_that_throws_an_exception() {
throw new RuntimeException('Execution failed');
}
public function test_filtering_of_get_comments() {
if ( ! $this->using_comment_logger() ) {
$this->assertTrue( true );
return;
}
$post_id = $this->factory->post->create_object(array(
'post_title' => __FUNCTION__,
));
$comment_id = $this->factory->comment->create_object(array(
'comment_post_ID' => $post_id,
'comment_author' => __CLASS__,
'comment_content' => __FUNCTION__,
));
// Verify that we're getting the expected comment before we add logging comments
$comments = get_comments();
$this->assertCount( 1, $comments );
$this->assertEquals( $comment_id, $comments[0]->comment_ID );
$action_id = as_schedule_single_action( time(), 'a hook' );
$logger = ActionScheduler::logger();
$message = 'Logging that something happened';
$log_id = $logger->log( $action_id, $message );
// Verify that logging comments are excluded from general comment queries
$comments = get_comments();
$this->assertCount( 1, $comments );
$this->assertEquals( $comment_id, $comments[0]->comment_ID );
// Verify that logging comments are returned when asking for them specifically
$comments = get_comments(array(
'type' => ActionScheduler_wpCommentLogger::TYPE,
));
// Expecting two: one when the action is created, another when we added our custom log
$this->assertCount( 2, $comments );
$this->assertContains( $log_id, wp_list_pluck($comments, 'comment_ID'));
}
private function using_comment_logger() {
if ( null === $this->use_comment_logger ) {
$this->use_comment_logger = ! ActionScheduler_DataController::dependencies_met();
}
return $this->use_comment_logger;
}
}

View File

@ -0,0 +1,145 @@
<?php
use Action_Scheduler\Migration\ActionMigrator;
use Action_Scheduler\Migration\LogMigrator;
/**
* Class ActionMigrator_Test
* @group migration
*/
class ActionMigrator_Test extends ActionScheduler_UnitTestCase {
public function setUp() {
parent::setUp();
if ( ! taxonomy_exists( ActionScheduler_wpPostStore::GROUP_TAXONOMY ) ) {
// register the post type and taxonomy necessary for the store to work
$store = new ActionScheduler_wpPostStore();
$store->init();
}
}
public function test_migrate_from_wpPost_to_db() {
$source = new ActionScheduler_wpPostStore();
$destination = new ActionScheduler_DBStore();
$migrator = new ActionMigrator( $source, $destination, $this->get_log_migrator() );
$time = as_get_datetime_object();
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule, 'my_group' );
$action_id = $source->save_action( $action );
$new_id = $migrator->migrate( $action_id );
// ensure we get the same record out of the new store as we stored in the old
$retrieved = $destination->fetch_action( $new_id );
$this->assertEquals( $action->get_hook(), $retrieved->get_hook() );
$this->assertEqualSets( $action->get_args(), $retrieved->get_args() );
$this->assertEquals( $action->get_schedule()->get_date()->format( 'U' ), $retrieved->get_schedule()->get_date()->format( 'U' ) );
$this->assertEquals( $action->get_group(), $retrieved->get_group() );
$this->assertEquals( \ActionScheduler_Store::STATUS_PENDING, $destination->get_status( $new_id ) );
// ensure that the record in the old store does not exist
$old_action = $source->fetch_action( $action_id );
$this->assertInstanceOf( 'ActionScheduler_NullAction', $old_action );
}
public function test_does_not_migrate_missing_action_from_wpPost_to_db() {
$source = new ActionScheduler_wpPostStore();
$destination = new ActionScheduler_DBStore();
$migrator = new ActionMigrator( $source, $destination, $this->get_log_migrator() );
$action_id = rand( 100, 100000 );
$new_id = $migrator->migrate( $action_id );
$this->assertEquals( 0, $new_id );
// ensure we get the same record out of the new store as we stored in the old
$retrieved = $destination->fetch_action( $new_id );
$this->assertInstanceOf( 'ActionScheduler_NullAction', $retrieved );
}
public function test_migrate_completed_action_from_wpPost_to_db() {
$source = new ActionScheduler_wpPostStore();
$destination = new ActionScheduler_DBStore();
$migrator = new ActionMigrator( $source, $destination, $this->get_log_migrator() );
$time = as_get_datetime_object();
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule, 'my_group' );
$action_id = $source->save_action( $action );
$source->mark_complete( $action_id );
$new_id = $migrator->migrate( $action_id );
// ensure we get the same record out of the new store as we stored in the old
$retrieved = $destination->fetch_action( $new_id );
$this->assertEquals( $action->get_hook(), $retrieved->get_hook() );
$this->assertEqualSets( $action->get_args(), $retrieved->get_args() );
$this->assertEquals( $action->get_schedule()->get_date()->format( 'U' ), $retrieved->get_schedule()->get_date()->format( 'U' ) );
$this->assertEquals( $action->get_group(), $retrieved->get_group() );
$this->assertTrue( $retrieved->is_finished() );
$this->assertEquals( \ActionScheduler_Store::STATUS_COMPLETE, $destination->get_status( $new_id ) );
// ensure that the record in the old store does not exist
$old_action = $source->fetch_action( $action_id );
$this->assertInstanceOf( 'ActionScheduler_NullAction', $old_action );
}
public function test_migrate_failed_action_from_wpPost_to_db() {
$source = new ActionScheduler_wpPostStore();
$destination = new ActionScheduler_DBStore();
$migrator = new ActionMigrator( $source, $destination, $this->get_log_migrator() );
$time = as_get_datetime_object();
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule, 'my_group' );
$action_id = $source->save_action( $action );
$source->mark_failure( $action_id );
$new_id = $migrator->migrate( $action_id );
// ensure we get the same record out of the new store as we stored in the old
$retrieved = $destination->fetch_action( $new_id );
$this->assertEquals( $action->get_hook(), $retrieved->get_hook() );
$this->assertEqualSets( $action->get_args(), $retrieved->get_args() );
$this->assertEquals( $action->get_schedule()->get_date()->format( 'U' ), $retrieved->get_schedule()->get_date()->format( 'U' ) );
$this->assertEquals( $action->get_group(), $retrieved->get_group() );
$this->assertTrue( $retrieved->is_finished() );
$this->assertEquals( \ActionScheduler_Store::STATUS_FAILED, $destination->get_status( $new_id ) );
// ensure that the record in the old store does not exist
$old_action = $source->fetch_action( $action_id );
$this->assertInstanceOf( 'ActionScheduler_NullAction', $old_action );
}
public function test_migrate_canceled_action_from_wpPost_to_db() {
$source = new ActionScheduler_wpPostStore();
$destination = new ActionScheduler_DBStore();
$migrator = new ActionMigrator( $source, $destination, $this->get_log_migrator() );
$time = as_get_datetime_object();
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule, 'my_group' );
$action_id = $source->save_action( $action );
$source->cancel_action( $action_id );
$new_id = $migrator->migrate( $action_id );
// ensure we get the same record out of the new store as we stored in the old
$retrieved = $destination->fetch_action( $new_id );
$this->assertEquals( $action->get_hook(), $retrieved->get_hook() );
$this->assertEqualSets( $action->get_args(), $retrieved->get_args() );
$this->assertEquals( $action->get_schedule()->get_date()->format( 'U' ), $retrieved->get_schedule()->get_date()->format( 'U' ) );
$this->assertEquals( $action->get_group(), $retrieved->get_group() );
$this->assertTrue( $retrieved->is_finished() );
$this->assertEquals( \ActionScheduler_Store::STATUS_CANCELED, $destination->get_status( $new_id ) );
// ensure that the record in the old store does not exist
$old_action = $source->fetch_action( $action_id );
$this->assertInstanceOf( 'ActionScheduler_NullAction', $old_action );
}
private function get_log_migrator() {
return new LogMigrator( \ActionScheduler::logger(), new ActionScheduler_DBLogger() );
}
}

View File

@ -0,0 +1,76 @@
<?php
use Action_Scheduler\Migration\BatchFetcher;
use ActionScheduler_wpPostStore as PostStore;
/**
* Class BatchFetcher_Test
* @group migration
*/
class BatchFetcher_Test extends ActionScheduler_UnitTestCase {
public function setUp() {
parent::setUp();
if ( ! taxonomy_exists( PostStore::GROUP_TAXONOMY ) ) {
// register the post type and taxonomy necessary for the store to work
$store = new PostStore();
$store->init();
}
}
public function test_nothing_to_migrate() {
$store = new PostStore();
$batch_fetcher = new BatchFetcher( $store );
$actions = $batch_fetcher->fetch();
$this->assertEmpty( $actions );
}
public function test_get_due_before_future() {
$store = new PostStore();
$due = [];
$future = [];
for ( $i = 0; $i < 5; $i ++ ) {
$time = as_get_datetime_object( $i + 1 . ' minutes' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule );
$future[] = $store->save_action( $action );
$time = as_get_datetime_object( $i + 1 . ' minutes ago' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule );
$due[] = $store->save_action( $action );
}
$batch_fetcher = new BatchFetcher( $store );
$actions = $batch_fetcher->fetch();
$this->assertEqualSets( $due, $actions );
}
public function test_get_future_before_complete() {
$store = new PostStore();
$future = [];
$complete = [];
for ( $i = 0; $i < 5; $i ++ ) {
$time = as_get_datetime_object( $i + 1 . ' minutes' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule );
$future[] = $store->save_action( $action );
$time = as_get_datetime_object( $i + 1 . ' minutes ago' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_FinishedAction( 'my_hook', [], $schedule );
$complete[] = $store->save_action( $action );
}
$batch_fetcher = new BatchFetcher( $store );
$actions = $batch_fetcher->fetch();
$this->assertEqualSets( $future, $actions );
}
}

View File

@ -0,0 +1,33 @@
<?php
use Action_Scheduler\Migration\Config;
/**
* Class Config_Test
* @group migration
*/
class Config_Test extends ActionScheduler_UnitTestCase {
public function test_source_store_required() {
$config = new Config();
$this->expectException( \RuntimeException::class );
$config->get_source_store();
}
public function test_source_logger_required() {
$config = new Config();
$this->expectException( \RuntimeException::class );
$config->get_source_logger();
}
public function test_destination_store_required() {
$config = new Config();
$this->expectException( \RuntimeException::class );
$config->get_destination_store();
}
public function test_destination_logger_required() {
$config = new Config();
$this->expectException( \RuntimeException::class );
$config->get_destination_logger();
}
}

View File

@ -0,0 +1,44 @@
<?php
use Action_Scheduler\Migration\LogMigrator;
/**
* Class LogMigrator_Test
* @group migration
*/
class LogMigrator_Test extends ActionScheduler_UnitTestCase {
function setUp() {
parent::setUp();
if ( ! taxonomy_exists( ActionScheduler_wpPostStore::GROUP_TAXONOMY ) ) {
// register the post type and taxonomy necessary for the store to work
$store = new ActionScheduler_wpPostStore();
$store->init();
}
}
public function test_migrate_from_wpComment_to_db() {
$source = new ActionScheduler_wpCommentLogger();
$destination = new ActionScheduler_DBLogger();
$migrator = new LogMigrator( $source, $destination );
$source_action_id = rand( 10, 10000 );
$destination_action_id = rand( 10, 10000 );
$logs = [];
for ( $i = 0 ; $i < 3 ; $i++ ) {
for ( $j = 0 ; $j < 5 ; $j++ ) {
$logs[ $i ][ $j ] = md5(rand());
if ( $i == 1 ) {
$source->log( $source_action_id, $logs[ $i ][ $j ] );
}
}
}
$migrator->migrate( $source_action_id, $destination_action_id );
$migrated = $destination->get_logs( $destination_action_id );
$this->assertEqualSets( $logs[ 1 ], array_map( function( $log ) { return $log->get_message(); }, $migrated ) );
// no API for deleting logs, so we leave them for manual cleanup later
$this->assertCount( 5, $source->get_logs( $source_action_id ) );
}
}

View File

@ -0,0 +1,92 @@
<?php
use Action_Scheduler\Migration\Config;
use Action_Scheduler\Migration\Runner;
use ActionScheduler_wpCommentLogger as CommentLogger;
use ActionScheduler_wpPostStore as PostStore;
/**
* Class Runner_Test
* @group migration
*/
class Runner_Test extends ActionScheduler_UnitTestCase {
public function setUp() {
parent::setUp();
if ( ! taxonomy_exists( PostStore::GROUP_TAXONOMY ) ) {
// register the post type and taxonomy necessary for the store to work
$store = new PostStore();
$store->init();
}
}
public function test_migrate_batches() {
$source_store = new PostStore();
$destination_store = new ActionScheduler_DBStore();
$source_logger = new CommentLogger();
$destination_logger = new ActionScheduler_DBLogger();
$config = new Config();
$config->set_source_store( $source_store );
$config->set_source_logger( $source_logger );
$config->set_destination_store( $destination_store );
$config->set_destination_logger( $destination_logger );
$runner = new Runner( $config );
$due = [];
$future = [];
$complete = [];
for ( $i = 0; $i < 5; $i ++ ) {
$time = as_get_datetime_object( $i + 1 . ' minutes' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule );
$future[] = $source_store->save_action( $action );
$time = as_get_datetime_object( $i + 1 . ' minutes ago' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule );
$due[] = $source_store->save_action( $action );
$time = as_get_datetime_object( $i + 1 . ' minutes ago' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_FinishedAction( 'my_hook', [], $schedule );
$complete[] = $source_store->save_action( $action );
}
$created = $source_store->query_actions( [ 'per_page' => 0 ] );
$this->assertCount( 15, $created );
$runner->run( 10 );
// due actions should migrate in the first batch
$migrated = $destination_store->query_actions( [ 'per_page' => 0, 'hook' => 'my_hook' ] );
$this->assertCount( 5, $migrated );
$remaining = $source_store->query_actions( [ 'per_page' => 0, 'hook' => 'my_hook' ] );
$this->assertCount( 10, $remaining );
$runner->run( 10 );
// pending actions should migrate in the second batch
$migrated = $destination_store->query_actions( [ 'per_page' => 0, 'hook' => 'my_hook' ] );
$this->assertCount( 10, $migrated );
$remaining = $source_store->query_actions( [ 'per_page' => 0, 'hook' => 'my_hook' ] );
$this->assertCount( 5, $remaining );
$runner->run( 10 );
// completed actions should migrate in the third batch
$migrated = $destination_store->query_actions( [ 'per_page' => 0, 'hook' => 'my_hook' ] );
$this->assertCount( 15, $migrated );
$remaining = $source_store->query_actions( [ 'per_page' => 0, 'hook' => 'my_hook' ] );
$this->assertCount( 0, $remaining );
}
}

View File

@ -0,0 +1,130 @@
<?php
use Action_Scheduler\Migration\Scheduler;
use ActionScheduler_wpPostStore as PostStore;
/**
* Class Scheduler_Test
* @group migration
*/
class Scheduler_Test extends ActionScheduler_UnitTestCase {
public function setUp() {
parent::setUp();
if ( ! taxonomy_exists( PostStore::GROUP_TAXONOMY ) ) {
// register the post type and taxonomy necessary for the store to work
$store = new PostStore();
$store->init();
}
}
public function test_migration_is_complete() {
ActionScheduler_DataController::mark_migration_complete();
$this->assertTrue( ActionScheduler_DataController::is_migration_complete() );
}
public function test_migration_is_not_complete() {
$this->assertFalse( ActionScheduler_DataController::is_migration_complete() );
update_option( ActionScheduler_DataController::STATUS_FLAG, 'something_random' );
$this->assertFalse( ActionScheduler_DataController::is_migration_complete() );
}
public function test_migration_is_scheduled() {
// Clear the any existing migration hooks that have already been setup.
as_unschedule_all_actions( Scheduler::HOOK );
$scheduler = new Scheduler();
$this->assertFalse(
$scheduler->is_migration_scheduled(),
'Migration is not automatically scheduled when a new ' . Scheduler::class . ' instance is created.'
);
$scheduler->schedule_migration();
$this->assertTrue(
$scheduler->is_migration_scheduled(),
'Migration is scheduled only after schedule_migration() has been called.'
);
}
public function test_scheduler_runs_migration() {
$source_store = new PostStore();
$destination_store = new ActionScheduler_DBStore();
$return_5 = function () {
return 5;
};
add_filter( 'action_scheduler/migration_batch_size', $return_5 );
// Make sure successive migration actions are delayed so all actions aren't migrated at once on separate hooks
$return_60 = function () {
return 60;
};
add_filter( 'action_scheduler/migration_interval', $return_60 );
for ( $i = 0; $i < 10; $i ++ ) {
$time = as_get_datetime_object( $i + 1 . ' minutes' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule );
$future[] = $source_store->save_action( $action );
$time = as_get_datetime_object( $i + 1 . ' minutes ago' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule );
$due[] = $source_store->save_action( $action );
}
$this->assertCount( 20, $source_store->query_actions( [ 'per_page' => 0 ] ) );
$scheduler = new Scheduler();
$scheduler->unschedule_migration();
$scheduler->schedule_migration( time() - 1 );
$queue_runner = ActionScheduler_Mocker::get_queue_runner( $destination_store );
$queue_runner->run();
// 5 actions should have moved from the source store when the queue runner triggered the migration action
$this->assertCount( 15, $source_store->query_actions( [ 'per_page' => 0, 'hook' => 'my_hook' ] ) );
remove_filter( 'action_scheduler/migration_batch_size', $return_5 );
remove_filter( 'action_scheduler/migration_interval', $return_60 );
}
public function test_scheduler_marks_itself_complete() {
$source_store = new PostStore();
$destination_store = new ActionScheduler_DBStore();
for ( $i = 0; $i < 5; $i ++ ) {
$time = as_get_datetime_object( $i + 1 . ' minutes ago' );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule );
$due[] = $source_store->save_action( $action );
}
$this->assertCount( 5, $source_store->query_actions( [ 'per_page' => 0 ] ) );
$scheduler = new Scheduler();
$scheduler->unschedule_migration();
$scheduler->schedule_migration( time() - 1 );
$queue_runner = ActionScheduler_Mocker::get_queue_runner( $destination_store );
$queue_runner->run();
// All actions should have moved from the source store when the queue runner triggered the migration action
$this->assertCount( 0, $source_store->query_actions( [ 'per_page' => 0, 'hook' => 'my_hook' ] ) );
// schedule another so we can get it to run immediately
$scheduler->unschedule_migration();
$scheduler->schedule_migration( time() - 1 );
// run again so it knows that there's nothing left to process
$queue_runner->run();
$scheduler->unhook();
// ensure the flag is set marking migration as complete
$this->assertTrue( ActionScheduler_DataController::is_migration_complete() );
// ensure that another instance has not been scheduled
$this->assertFalse( $scheduler->is_migration_scheduled() );
}
}

View File

@ -0,0 +1,259 @@
<?php
/**
* Class procedural_api_Test
*/
class procedural_api_Test extends ActionScheduler_UnitTestCase {
public function test_schedule_action() {
$time = time();
$hook = md5(rand());
$action_id = as_schedule_single_action( $time, $hook );
$store = ActionScheduler::store();
$action = $store->fetch_action($action_id);
$this->assertEquals( $time, $action->get_schedule()->get_date()->getTimestamp() );
$this->assertEquals( $hook, $action->get_hook() );
}
public function test_recurring_action() {
$time = time();
$hook = md5(rand());
$action_id = as_schedule_recurring_action( $time, HOUR_IN_SECONDS, $hook );
$store = ActionScheduler::store();
$action = $store->fetch_action($action_id);
$this->assertEquals( $time, $action->get_schedule()->get_date()->getTimestamp() );
$this->assertEquals( $time + HOUR_IN_SECONDS + 2, $action->get_schedule()->get_next(as_get_datetime_object($time + 2))->getTimestamp());
$this->assertEquals( $hook, $action->get_hook() );
}
public function test_cron_schedule() {
$time = as_get_datetime_object('2014-01-01');
$hook = md5(rand());
$action_id = as_schedule_cron_action( $time->getTimestamp(), '0 0 10 10 *', $hook );
$store = ActionScheduler::store();
$action = $store->fetch_action($action_id);
$expected_date = as_get_datetime_object('2014-10-10');
$this->assertEquals( $expected_date->getTimestamp(), $action->get_schedule()->get_date()->getTimestamp() );
$this->assertEquals( $hook, $action->get_hook() );
$expected_date = as_get_datetime_object( '2015-10-10' );
$this->assertEquals( $expected_date->getTimestamp(), $action->get_schedule()->get_next( as_get_datetime_object( '2015-01-02' ) )->getTimestamp() );
}
public function test_get_next() {
$time = as_get_datetime_object('tomorrow');
$hook = md5(rand());
as_schedule_recurring_action( $time->getTimestamp(), HOUR_IN_SECONDS, $hook );
$next = as_next_scheduled_action( $hook );
$this->assertEquals( $time->getTimestamp(), $next );
}
public function test_get_next_async() {
$hook = md5(rand());
$action_id = as_enqueue_async_action( $hook );
$next = as_next_scheduled_action( $hook );
$this->assertTrue( $next );
$store = ActionScheduler::store();
// Completed async actions should still return false
$store->mark_complete( $action_id );
$next = as_next_scheduled_action( $hook );
$this->assertFalse( $next );
// Failed async actions should still return false
$store->mark_failure( $action_id );
$next = as_next_scheduled_action( $hook );
$this->assertFalse( $next );
// Cancelled async actions should still return false
$store->cancel_action( $action_id );
$next = as_next_scheduled_action( $hook );
$this->assertFalse( $next );
}
public function provider_time_hook_args_group() {
$time = time() + 60 * 2;
$hook = md5( rand() );
$args = array( rand(), rand() );
$group = 'test_group';
return array(
// Test with no args or group
array(
'time' => $time,
'hook' => $hook,
'args' => array(),
'group' => '',
),
// Test with args but no group
array(
'time' => $time,
'hook' => $hook,
'args' => $args,
'group' => '',
),
// Test with group but no args
array(
'time' => $time,
'hook' => $hook,
'args' => array(),
'group' => $group,
),
// Test with args & group
array(
'time' => $time,
'hook' => $hook,
'args' => $args,
'group' => $group,
),
);
}
/**
* @dataProvider provider_time_hook_args_group
*/
public function test_unschedule( $time, $hook, $args, $group ) {
$action_id_unscheduled = as_schedule_single_action( $time, $hook, $args, $group );
$action_scheduled_time = $time + 1;
$action_id_scheduled = as_schedule_single_action( $action_scheduled_time, $hook, $args, $group );
as_unschedule_action( $hook, $args, $group );
$next = as_next_scheduled_action( $hook, $args, $group );
$this->assertEquals( $action_scheduled_time, $next );
$store = ActionScheduler::store();
$unscheduled_action = $store->fetch_action( $action_id_unscheduled );
// Make sure the next scheduled action is unscheduled
$this->assertEquals( $hook, $unscheduled_action->get_hook() );
$this->assertEquals( as_get_datetime_object($time), $unscheduled_action->get_schedule()->get_date() );
$this->assertEquals( ActionScheduler_Store::STATUS_CANCELED, $store->get_status( $action_id_unscheduled ) );
$this->assertNull( $unscheduled_action->get_schedule()->get_next( as_get_datetime_object() ) );
// Make sure other scheduled actions are not unscheduled
$this->assertEquals( ActionScheduler_Store::STATUS_PENDING, $store->get_status( $action_id_scheduled ) );
$scheduled_action = $store->fetch_action( $action_id_scheduled );
$this->assertEquals( $hook, $scheduled_action->get_hook() );
$this->assertEquals( $action_scheduled_time, $scheduled_action->get_schedule()->get_date()->getTimestamp() );
}
/**
* @dataProvider provider_time_hook_args_group
*/
public function test_unschedule_all( $time, $hook, $args, $group ) {
$hook = md5( $hook );
$action_ids = array();
for ( $i = 0; $i < 3; $i++ ) {
$action_ids[] = as_schedule_single_action( $time, $hook, $args, $group );
}
as_unschedule_all_actions( $hook, $args, $group );
$next = as_next_scheduled_action( $hook );
$this->assertFalse($next);
$after = as_get_datetime_object( $time );
$after->modify( '+1 minute' );
$store = ActionScheduler::store();
foreach ( $action_ids as $action_id ) {
$action = $store->fetch_action($action_id);
$this->assertEquals( $hook, $action->get_hook() );
$this->assertEquals( as_get_datetime_object( $time ), $action->get_schedule()->get_date() );
$this->assertEquals( ActionScheduler_Store::STATUS_CANCELED, $store->get_status( $action_id ) );
$this->assertNull( $action->get_schedule()->get_next( $after ) );
}
}
public function test_as_get_datetime_object_default() {
$utc_now = new ActionScheduler_DateTime(null, new DateTimeZone('UTC'));
$as_now = as_get_datetime_object();
// Don't want to use 'U' as timestamps will always be in UTC
$this->assertEquals($utc_now->format('Y-m-d H:i:s'),$as_now->format('Y-m-d H:i:s'));
}
public function test_as_get_datetime_object_relative() {
$utc_tomorrow = new ActionScheduler_DateTime('tomorrow', new DateTimeZone('UTC'));
$as_tomorrow = as_get_datetime_object('tomorrow');
$this->assertEquals($utc_tomorrow->format('Y-m-d H:i:s'),$as_tomorrow->format('Y-m-d H:i:s'));
$utc_tomorrow = new ActionScheduler_DateTime('yesterday', new DateTimeZone('UTC'));
$as_tomorrow = as_get_datetime_object('yesterday');
$this->assertEquals($utc_tomorrow->format('Y-m-d H:i:s'),$as_tomorrow->format('Y-m-d H:i:s'));
}
public function test_as_get_datetime_object_fixed() {
$utc_tomorrow = new ActionScheduler_DateTime('29 February 2016', new DateTimeZone('UTC'));
$as_tomorrow = as_get_datetime_object('29 February 2016');
$this->assertEquals($utc_tomorrow->format('Y-m-d H:i:s'),$as_tomorrow->format('Y-m-d H:i:s'));
$utc_tomorrow = new ActionScheduler_DateTime('1st January 2024', new DateTimeZone('UTC'));
$as_tomorrow = as_get_datetime_object('1st January 2024');
$this->assertEquals($utc_tomorrow->format('Y-m-d H:i:s'),$as_tomorrow->format('Y-m-d H:i:s'));
}
public function test_as_get_datetime_object_timezone() {
$timezone_au = 'Australia/Brisbane';
$timezone_default = date_default_timezone_get();
date_default_timezone_set( $timezone_au );
$au_now = new ActionScheduler_DateTime(null);
$as_now = as_get_datetime_object();
// Make sure they're for the same time
$this->assertEquals($au_now->getTimestamp(),$as_now->getTimestamp());
// But not in the same timezone, as $as_now should be using UTC
$this->assertNotEquals($au_now->format('Y-m-d H:i:s'),$as_now->format('Y-m-d H:i:s'));
$au_now = new ActionScheduler_DateTime(null);
$as_au_now = as_get_datetime_object();
$this->assertEquals( $au_now->getTimestamp(), $as_now->getTimestamp(), '', 2 );
// But not in the same timezone, as $as_now should be using UTC
$this->assertNotEquals($au_now->format('Y-m-d H:i:s'),$as_now->format('Y-m-d H:i:s'));
// Just in cases
date_default_timezone_set( $timezone_default );
}
public function test_as_get_datetime_object_type() {
$f = 'Y-m-d H:i:s';
$now = as_get_datetime_object();
$this->assertInstanceOf( 'ActionScheduler_DateTime', $now );
$dateTime = new DateTime( 'now', new DateTimeZone( 'UTC' ) );
$asDateTime = as_get_datetime_object( $dateTime );
$this->assertEquals( $dateTime->format( $f ), $asDateTime->format( $f ) );
}
}

View File

@ -0,0 +1,100 @@
<?php
/**
* Class as_get_scheduled_actions_Test
*/
class as_get_scheduled_actions_Test extends ActionScheduler_UnitTestCase {
private $hooks = array();
private $args = array();
private $groups = array();
public function setUp() {
parent::setUp();
$store = ActionScheduler::store();
for ( $i = 0 ; $i < 10 ; $i++ ) {
$this->hooks[$i] = md5(rand());
$this->args[$i] = md5(rand());
$this->groups[$i] = md5(rand());
}
for ( $i = 0 ; $i < 10 ; $i++ ) {
for ( $j = 0 ; $j < 10 ; $j++ ) {
$schedule = new ActionScheduler_SimpleSchedule( as_get_datetime_object( $j - 3 . 'days') );
$group = $this->groups[ ( $i + $j ) % 10 ];
$action = new ActionScheduler_Action( $this->hooks[$i], array($this->args[$j]), $schedule, $group );
$store->save_action( $action );
}
}
}
public function test_date_queries() {
$actions = as_get_scheduled_actions(array(
'date' => as_get_datetime_object(gmdate('Y-m-d 00:00:00')),
'per_page' => -1,
), 'ids');
$this->assertCount(30, $actions);
$actions = as_get_scheduled_actions(array(
'date' => as_get_datetime_object(gmdate('Y-m-d 00:00:00')),
'date_compare' => '>=',
'per_page' => -1,
), 'ids');
$this->assertCount(70, $actions);
}
public function test_hook_queries() {
$actions = as_get_scheduled_actions(array(
'hook' => $this->hooks[2],
'per_page' => -1,
), 'ids');
$this->assertCount(10, $actions);
$actions = as_get_scheduled_actions(array(
'hook' => $this->hooks[2],
'date' => as_get_datetime_object(gmdate('Y-m-d 00:00:00')),
'per_page' => -1,
), 'ids');
$this->assertCount(3, $actions);
}
public function test_args_queries() {
$actions = as_get_scheduled_actions(array(
'args' => array($this->args[5]),
'per_page' => -1,
), 'ids');
$this->assertCount(10, $actions);
$actions = as_get_scheduled_actions(array(
'args' => array($this->args[5]),
'hook' => $this->hooks[3],
'per_page' => -1,
), 'ids');
$this->assertCount(1, $actions);
$actions = as_get_scheduled_actions(array(
'args' => array($this->args[5]),
'hook' => $this->hooks[3],
'date' => as_get_datetime_object(gmdate('Y-m-d 00:00:00')),
'per_page' => -1,
), 'ids');
$this->assertCount(0, $actions);
}
public function test_group_queries() {
$actions = as_get_scheduled_actions(array(
'group' => $this->groups[1],
'per_page' => -1,
), 'ids');
$this->assertCount(10, $actions);
$actions = as_get_scheduled_actions(array(
'group' => $this->groups[1],
'hook' => $this->hooks[9],
'per_page' => -1,
), 'ids');
$this->assertCount(1, $actions);
}
}

View File

@ -0,0 +1,154 @@
<?php
/**
* Class ActionScheduler_QueueCleaner_Test
*/
class ActionScheduler_QueueCleaner_Test extends ActionScheduler_UnitTestCase {
public function test_delete_old_actions() {
$store = ActionScheduler::store();
$runner = ActionScheduler_Mocker::get_queue_runner( $store );
$random = md5(rand());
$schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('1 day ago'));
$created_actions = array();
for ( $i = 0 ; $i < 5 ; $i++ ) {
$action = new ActionScheduler_Action( $random, array($random), $schedule );
$created_actions[] = $store->save_action( $action );
}
$runner->run();
add_filter( 'action_scheduler_retention_period', '__return_zero' ); // delete any finished job
$cleaner = new ActionScheduler_QueueCleaner( $store );
$cleaner->delete_old_actions();
remove_filter( 'action_scheduler_retention_period', '__return_zero' );
foreach ( $created_actions as $action_id ) {
$action = $store->fetch_action($action_id);
$this->assertFalse($action->is_finished()); // it's a NullAction
}
}
public function test_delete_canceled_actions() {
$store = ActionScheduler::store();
$random = md5(rand());
$schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('1 day ago'));
$created_actions = array();
for ( $i = 0 ; $i < 5 ; $i++ ) {
$action = new ActionScheduler_Action( $random, array($random), $schedule );
$action_id = $store->save_action( $action );
$store->cancel_action( $action_id );
$created_actions[] = $action_id;
}
// track the actions that are deleted
$mock_action = new MockAction();
add_action( 'action_scheduler_deleted_action', array( $mock_action, 'action' ), 10, 1 );
add_filter( 'action_scheduler_retention_period', '__return_zero' ); // delete any finished job
$cleaner = new ActionScheduler_QueueCleaner( $store );
$cleaner->delete_old_actions();
remove_filter( 'action_scheduler_retention_period', '__return_zero' );
remove_action( 'action_scheduler_deleted_action', array( $mock_action, 'action' ), 10 );
$deleted_actions = array();
foreach ( $mock_action->get_args() as $action ) {
$deleted_actions[] = reset( $action );
}
$this->assertEqualSets( $created_actions, $deleted_actions );
}
public function test_do_not_delete_recent_actions() {
$store = ActionScheduler::store();
$runner = ActionScheduler_Mocker::get_queue_runner( $store );
$random = md5(rand());
$schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('1 day ago'));
$created_actions = array();
for ( $i = 0 ; $i < 5 ; $i++ ) {
$action = new ActionScheduler_Action( $random, array($random), $schedule );
$created_actions[] = $store->save_action( $action );
}
$runner->run();
$cleaner = new ActionScheduler_QueueCleaner( $store );
$cleaner->delete_old_actions();
foreach ( $created_actions as $action_id ) {
$action = $store->fetch_action($action_id);
$this->assertTrue($action->is_finished()); // It's a FinishedAction
}
}
public function test_reset_unrun_actions() {
$store = ActionScheduler::store();
$random = md5(rand());
$schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('1 day ago'));
$created_actions = array();
for ( $i = 0 ; $i < 5 ; $i++ ) {
$action = new ActionScheduler_Action( $random, array($random), $schedule );
$created_actions[] = $store->save_action( $action );
}
$store->stake_claim(10);
// don't actually process the jobs, to simulate a request that timed out
add_filter( 'action_scheduler_timeout_period', '__return_zero' ); // delete any finished job
$cleaner = new ActionScheduler_QueueCleaner( $store );
$cleaner->reset_timeouts();
remove_filter( 'action_scheduler_timeout_period', '__return_zero' );
$claim = $store->stake_claim(10);
$this->assertEqualSets($created_actions, $claim->get_actions());
}
public function test_do_not_reset_failed_action() {
$store = ActionScheduler::store();
$random = md5(rand());
$schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('1 day ago'));
$created_actions = array();
for ( $i = 0 ; $i < 5 ; $i++ ) {
$action = new ActionScheduler_Action( $random, array($random), $schedule );
$created_actions[] = $store->save_action( $action );
}
$claim = $store->stake_claim(10);
foreach ( $claim->get_actions() as $action_id ) {
// simulate the first action interrupted by an uncatchable fatal error
$store->log_execution( $action_id );
break;
}
add_filter( 'action_scheduler_timeout_period', '__return_zero' ); // delete any finished job
$cleaner = new ActionScheduler_QueueCleaner( $store );
$cleaner->reset_timeouts();
remove_filter( 'action_scheduler_timeout_period', '__return_zero' );
$new_claim = $store->stake_claim(10);
$this->assertCount( 4, $new_claim->get_actions() );
add_filter( 'action_scheduler_failure_period', '__return_zero' );
$cleaner->mark_failures();
remove_filter( 'action_scheduler_failure_period', '__return_zero' );
$failed = $store->query_actions(array('status' => ActionScheduler_Store::STATUS_FAILED));
$this->assertEquals( $created_actions[0], $failed[0] );
$this->assertCount( 1, $failed );
}
}

View File

@ -0,0 +1,330 @@
<?php
/**
* Class ActionScheduler_QueueRunner_Test
* @group runners
*/
class ActionScheduler_QueueRunner_Test extends ActionScheduler_UnitTestCase {
public function test_create_runner() {
$store = ActionScheduler::store();
$runner = ActionScheduler_Mocker::get_queue_runner( $store );
$actions_run = $runner->run();
$this->assertEquals( 0, $actions_run );
}
public function test_run() {
$store = ActionScheduler::store();
$runner = ActionScheduler_Mocker::get_queue_runner( $store );
$mock = new MockAction();
$random = md5(rand());
add_action( $random, array( $mock, 'action' ) );
$schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('1 day ago'));
for ( $i = 0 ; $i < 5 ; $i++ ) {
$action = new ActionScheduler_Action( $random, array($random), $schedule );
$store->save_action( $action );
}
$actions_run = $runner->run();
remove_action( $random, array( $mock, 'action' ) );
$this->assertEquals( 5, $mock->get_call_count() );
$this->assertEquals( 5, $actions_run );
}
public function test_run_with_future_actions() {
$store = ActionScheduler::store();
$runner = ActionScheduler_Mocker::get_queue_runner( $store );
$mock = new MockAction();
$random = md5(rand());
add_action( $random, array( $mock, 'action' ) );
$schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('1 day ago'));
for ( $i = 0 ; $i < 3 ; $i++ ) {
$action = new ActionScheduler_Action( $random, array($random), $schedule );
$store->save_action( $action );
}
$schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('tomorrow'));
for ( $i = 0 ; $i < 3 ; $i++ ) {
$action = new ActionScheduler_Action( $random, array($random), $schedule );
$store->save_action( $action );
}
$actions_run = $runner->run();
remove_action( $random, array( $mock, 'action' ) );
$this->assertEquals( 3, $mock->get_call_count() );
$this->assertEquals( 3, $actions_run );
}
public function test_completed_action_status() {
$store = ActionScheduler::store();
$runner = ActionScheduler_Mocker::get_queue_runner( $store );
$random = md5(rand());
$schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('12 hours ago'));
$action = new ActionScheduler_Action( $random, array(), $schedule );
$action_id = $store->save_action( $action );
$runner->run();
$finished_action = $store->fetch_action( $action_id );
$this->assertTrue( $finished_action->is_finished() );
}
public function test_next_instance_of_cron_action() {
// Create an action with daily Cron expression (i.e. midnight each day)
$random = md5( rand() );
$action_id = ActionScheduler::factory()->cron( $random, array(), null, '0 0 * * *' );
$store = ActionScheduler::store();
$runner = ActionScheduler_Mocker::get_queue_runner( $store );
// Make sure the 1st instance of the action is scheduled to occur tomorrow
$date = as_get_datetime_object( 'tomorrow' );
$date->modify( '-1 minute' );
$claim = $store->stake_claim( 10, $date );
$this->assertCount( 0, $claim->get_actions() );
$store->release_claim( $claim );
$date->modify( '+1 minute' );
$claim = $store->stake_claim( 10, $date );
$actions = $claim->get_actions();
$this->assertCount( 1, $actions );
$fetched_action_id = reset( $actions );
$fetched_action = $store->fetch_action( $fetched_action_id );
$this->assertEquals( $fetched_action_id, $action_id );
$this->assertEquals( $random, $fetched_action->get_hook() );
$this->assertEquals( $date->getTimestamp(), $fetched_action->get_schedule()->get_date()->getTimestamp(), '', 1 );
$store->release_claim( $claim );
// Make sure the 2nd instance of the cron action is scheduled to occur tomorrow still
$runner->process_action( $action_id );
$claim = $store->stake_claim( 10, $date );
$actions = $claim->get_actions();
$this->assertCount( 1, $actions );
$fetched_action_id = reset( $actions );
$fetched_action = $store->fetch_action( $fetched_action_id );
$this->assertNotEquals( $fetched_action_id, $action_id );
$this->assertEquals( $random, $fetched_action->get_hook() );
$this->assertEquals( $date->getTimestamp(), $fetched_action->get_schedule()->get_date()->getTimestamp(), '', 1 );
}
public function test_next_instance_of_interval_action() {
// Create an action to recur every 24 hours, with the first instance scheduled to run 12 hours ago
$random = md5( rand() );
$date = as_get_datetime_object( '12 hours ago' );
$action_id = ActionScheduler::factory()->recurring( $random, array(), $date->getTimestamp(), DAY_IN_SECONDS );
$store = ActionScheduler::store();
$runner = ActionScheduler_Mocker::get_queue_runner( $store );
// Make sure the 1st instance of the action is scheduled to occur 12 hours ago
$claim = $store->stake_claim( 10, $date );
$actions = $claim->get_actions();
$this->assertCount( 1, $actions );
$fetched_action_id = reset( $actions );
$fetched_action = $store->fetch_action( $fetched_action_id );
$this->assertEquals( $fetched_action_id, $action_id );
$this->assertEquals( $random, $fetched_action->get_hook() );
$this->assertEquals( $date->getTimestamp(), $fetched_action->get_schedule()->get_date()->getTimestamp(), '', 1 );
$store->release_claim( $claim );
// Make sure after the queue is run, the 2nd instance of the action is scheduled to occur in 24 hours
$runner->run();
$date = as_get_datetime_object( '+1 day' );
$claim = $store->stake_claim( 10, $date );
$actions = $claim->get_actions();
$this->assertCount( 1, $actions );
$fetched_action_id = reset( $actions );
$fetched_action = $store->fetch_action( $fetched_action_id );
$this->assertNotEquals( $fetched_action_id, $action_id );
$this->assertEquals( $random, $fetched_action->get_hook() );
$this->assertEquals( $date->getTimestamp(), $fetched_action->get_schedule()->get_date()->getTimestamp(), '', 1 );
$store->release_claim( $claim );
// Make sure the 3rd instance of the cron action is scheduled for 24 hours from now, as the action was run early, ahead of schedule
$runner->process_action( $fetched_action_id );
$date = as_get_datetime_object( '+1 day' );
$claim = $store->stake_claim( 10, $date );
$actions = $claim->get_actions();
$this->assertCount( 1, $actions );
$fetched_action_id = reset( $actions );
$fetched_action = $store->fetch_action( $fetched_action_id );
$this->assertNotEquals( $fetched_action_id, $action_id );
$this->assertEquals( $random, $fetched_action->get_hook() );
$this->assertEquals( $date->getTimestamp(), $fetched_action->get_schedule()->get_date()->getTimestamp(), '', 1 );
}
public function test_hooked_into_wp_cron() {
$next = wp_next_scheduled( ActionScheduler_QueueRunner::WP_CRON_HOOK, array( 'WP Cron' ) );
$this->assertNotEmpty($next);
}
public function test_batch_count_limit() {
$store = ActionScheduler::store();
$runner = ActionScheduler_Mocker::get_queue_runner( $store );
$mock = new MockAction();
$random = md5(rand());
add_action( $random, array( $mock, 'action' ) );
$schedule = new ActionScheduler_SimpleSchedule(new ActionScheduler_DateTime('1 day ago'));
for ( $i = 0 ; $i < 2 ; $i++ ) {
$action = new ActionScheduler_Action( $random, array($random), $schedule );
$store->save_action( $action );
}
$claim = $store->stake_claim();
$actions_run = $runner->run();
$this->assertEquals( 0, $mock->get_call_count() );
$this->assertEquals( 0, $actions_run );
$store->release_claim( $claim );
$actions_run = $runner->run();
$this->assertEquals( 2, $mock->get_call_count() );
$this->assertEquals( 2, $actions_run );
remove_action( $random, array( $mock, 'action' ) );
}
public function test_changing_batch_count_limit() {
$store = ActionScheduler::store();
$runner = ActionScheduler_Mocker::get_queue_runner( $store );
$random = md5(rand());
$schedule = new ActionScheduler_SimpleSchedule(new ActionScheduler_DateTime('1 day ago'));
for ( $i = 0 ; $i < 30 ; $i++ ) {
$action = new ActionScheduler_Action( $random, array($random), $schedule );
$store->save_action( $action );
}
$claims = array();
for ( $i = 0 ; $i < 5 ; $i++ ) {
$claims[] = $store->stake_claim( 5 );
}
$mock1 = new MockAction();
add_action( $random, array( $mock1, 'action' ) );
$actions_run = $runner->run();
remove_action( $random, array( $mock1, 'action' ) );
$this->assertEquals( 0, $mock1->get_call_count() );
$this->assertEquals( 0, $actions_run );
add_filter( 'action_scheduler_queue_runner_concurrent_batches', array( $this, 'return_6' ) );
$mock2 = new MockAction();
add_action( $random, array( $mock2, 'action' ) );
$actions_run = $runner->run();
remove_action( $random, array( $mock2, 'action' ) );
$this->assertEquals( 5, $mock2->get_call_count() );
$this->assertEquals( 5, $actions_run );
remove_filter( 'action_scheduler_queue_runner_concurrent_batches', array( $this, 'return_6' ) );
for ( $i = 0 ; $i < 5 ; $i++ ) { // to make up for the actions we just processed
$action = new ActionScheduler_Action( $random, array($random), $schedule );
$store->save_action( $action );
}
$mock3 = new MockAction();
add_action( $random, array( $mock3, 'action' ) );
$actions_run = $runner->run();
remove_action( $random, array( $mock3, 'action' ) );
$this->assertEquals( 0, $mock3->get_call_count() );
$this->assertEquals( 0, $actions_run );
remove_filter( 'action_scheduler_queue_runner_concurrent_batches', array( $this, 'return_6' ) );
}
public function return_6() {
return 6;
}
public function test_store_fetch_action_failure_schedule_next_instance() {
$random = md5( rand() );
$schedule = new ActionScheduler_IntervalSchedule( as_get_datetime_object( '12 hours ago' ), DAY_IN_SECONDS );
$action = new ActionScheduler_Action( $random, array(), $schedule );
$action_id = ActionScheduler::store()->save_action( $action );
// Set up a mock store that will throw an exception when fetching actions.
$store = $this
->getMockBuilder( 'ActionScheduler_wpPostStore' )
->setMethods( array( 'fetch_action' ) )
->getMock();
$store
->method( 'fetch_action' )
->with( $action_id )
->will( $this->throwException( new Exception() ) );
// Set up a mock queue runner to verify that schedule_next_instance()
// isn't called for an undefined $action.
$runner = $this
->getMockBuilder( 'ActionScheduler_QueueRunner' )
->setConstructorArgs( array( $store ) )
->setMethods( array( 'schedule_next_instance' ) )
->getMock();
$runner
->expects( $this->never() )
->method( 'schedule_next_instance' );
$runner->run();
// Set up a mock store that will throw an exception when fetching actions.
$store2 = $this
->getMockBuilder( 'ActionScheduler_wpPostStore' )
->setMethods( array( 'fetch_action' ) )
->getMock();
$store2
->method( 'fetch_action' )
->with( $action_id )
->willReturn( null );
// Set up a mock queue runner to verify that schedule_next_instance()
// isn't called for an undefined $action.
$runner2 = $this
->getMockBuilder( 'ActionScheduler_QueueRunner' )
->setConstructorArgs( array( $store ) )
->setMethods( array( 'schedule_next_instance' ) )
->getMock();
$runner2
->expects( $this->never() )
->method( 'schedule_next_instance' );
$runner2->run();
}
}

View File

@ -0,0 +1,76 @@
<?php
/**
* Class ActionScheduler_CronSchedule_Test
* @group schedules
*/
class ActionScheduler_CronSchedule_Test extends ActionScheduler_UnitTestCase {
public function test_creation() {
$time = as_get_datetime_object('tomorrow');
$cron = CronExpression::factory('@daily');
$start = clone $time;
$start->modify( '-1 hour' );
$schedule = new ActionScheduler_CronSchedule( $start, $cron );
$this->assertEquals( $time, $schedule->get_date() );
$this->assertEquals( $start, $schedule->get_first_date() );
// Test delaying for a future start date
$start->modify( '+1 week' );
$time->modify( '+1 week' );
$schedule = new ActionScheduler_CronSchedule( $start, $cron );
$this->assertEquals( $time, $schedule->get_date() );
$this->assertEquals( $start, $schedule->get_first_date() );
}
public function test_creation_with_first_date() {
$time = as_get_datetime_object( 'tomorrow' );
$cron = CronExpression::factory( '@daily' );
$start = clone $time;
$start->modify( '-1 hour' );
$schedule = new ActionScheduler_CronSchedule( $start, $cron );
$this->assertEquals( $time, $schedule->get_date() );
$this->assertEquals( $start, $schedule->get_first_date() );
// Test delaying for a future start date
$first = clone $time;
$first->modify( '-1 day' );
$start->modify( '+1 week' );
$time->modify( '+1 week' );
$schedule = new ActionScheduler_CronSchedule( $start, $cron, $first );
$this->assertEquals( $time, $schedule->get_date() );
$this->assertEquals( $first, $schedule->get_first_date() );
}
public function test_next() {
$time = as_get_datetime_object('2013-06-14');
$cron = CronExpression::factory('@daily');
$schedule = new ActionScheduler_CronSchedule($time, $cron);
$this->assertEquals( as_get_datetime_object('tomorrow'), $schedule->get_next( as_get_datetime_object() ) );
}
public function test_is_recurring() {
$schedule = new ActionScheduler_CronSchedule(as_get_datetime_object('2013-06-14'), CronExpression::factory('@daily'));
$this->assertTrue( $schedule->is_recurring() );
}
public function test_cron_format() {
$time = as_get_datetime_object('2014-01-01');
$cron = CronExpression::factory('0 0 10 10 *');
$schedule = new ActionScheduler_CronSchedule($time, $cron);
$this->assertEquals( as_get_datetime_object('2014-10-10'), $schedule->get_date() );
$cron = CronExpression::factory('0 0 L 1/2 *');
$schedule = new ActionScheduler_CronSchedule($time, $cron);
$this->assertEquals( as_get_datetime_object('2014-01-31'), $schedule->get_date() );
$this->assertEquals( as_get_datetime_object('2014-07-31'), $schedule->get_next( as_get_datetime_object('2014-06-01') ) );
$this->assertEquals( as_get_datetime_object('2028-11-30'), $schedule->get_next( as_get_datetime_object('2028-11-01') ) );
$cron = CronExpression::factory('30 14 * * MON#3 *');
$schedule = new ActionScheduler_CronSchedule($time, $cron);
$this->assertEquals( as_get_datetime_object('2014-01-20 14:30:00'), $schedule->get_date() );
$this->assertEquals( as_get_datetime_object('2014-05-19 14:30:00'), $schedule->get_next( as_get_datetime_object('2014-05-01') ) );
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* Class ActionScheduler_IntervalSchedule_Test
* @group schedules
*/
class ActionScheduler_IntervalSchedule_Test extends ActionScheduler_UnitTestCase {
public function test_creation() {
$time = as_get_datetime_object();
$schedule = new ActionScheduler_IntervalSchedule($time, HOUR_IN_SECONDS);
$this->assertEquals( $time, $schedule->get_date() );
$this->assertEquals( $time, $schedule->get_first_date() );
}
public function test_creation_with_first_date() {
$first = as_get_datetime_object();
$time = as_get_datetime_object( '+12 hours' );
$schedule = new ActionScheduler_IntervalSchedule( $time, HOUR_IN_SECONDS, $first );
$this->assertEquals( $time, $schedule->get_date() );
$this->assertEquals( $first, $schedule->get_first_date() );
}
public function test_next() {
$now = time();
$start = $now - 30;
$schedule = new ActionScheduler_IntervalSchedule( as_get_datetime_object("@$start"), MINUTE_IN_SECONDS );
$this->assertEquals( $start, $schedule->get_date()->getTimestamp() );
$this->assertEquals( $now + MINUTE_IN_SECONDS, $schedule->get_next(as_get_datetime_object())->getTimestamp() );
$this->assertEquals( $start, $schedule->get_next( as_get_datetime_object( "@$start" ) )->getTimestamp() );
}
public function test_is_recurring() {
$start = time() - 30;
$schedule = new ActionScheduler_IntervalSchedule( as_get_datetime_object("@$start"), MINUTE_IN_SECONDS );
$this->assertTrue( $schedule->is_recurring() );
}
}

View File

@ -0,0 +1,18 @@
<?php
/**
* Class ActionScheduler_NullSchedule_Test
* @group schedules
*/
class ActionScheduler_NullSchedule_Test extends ActionScheduler_UnitTestCase {
public function test_null_schedule() {
$schedule = new ActionScheduler_NullSchedule();
$this->assertNull( $schedule->get_date() );
}
public function test_is_recurring() {
$schedule = new ActionScheduler_NullSchedule();
$this->assertFalse( $schedule->is_recurring() );
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* Class ActionScheduler_SimpleSchedule_Test
* @group schedules
*/
class ActionScheduler_SimpleSchedule_Test extends ActionScheduler_UnitTestCase {
public function test_creation() {
$time = as_get_datetime_object();
$schedule = new ActionScheduler_SimpleSchedule($time);
$this->assertEquals( $time, $schedule->get_date() );
}
public function test_past_date() {
$time = as_get_datetime_object('-1 day');
$schedule = new ActionScheduler_SimpleSchedule($time);
$this->assertEquals( $time, $schedule->get_date() );
}
public function test_future_date() {
$time = as_get_datetime_object('+1 day');
$schedule = new ActionScheduler_SimpleSchedule($time);
$this->assertEquals( $time, $schedule->get_date() );
}
public function test_grace_period_for_next() {
$time = as_get_datetime_object('3 seconds ago');
$schedule = new ActionScheduler_SimpleSchedule($time);
$this->assertEquals( $time, $schedule->get_date() );
}
public function test_is_recurring() {
$schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('+1 day'));
$this->assertFalse( $schedule->is_recurring() );
}
}

View File

@ -0,0 +1,43 @@
<?php
/**
* Class ActionScheduler_Versions_Test
*/
class ActionScheduler_Versions_Test extends ActionScheduler_UnitTestCase {
public function test_register_version() {
$versions = new ActionScheduler_Versions();
$versions->register('1.0-dev', 'callback_1_dot_0_dev');
$versions->register('1.0', 'callback_1_dot_0');
$registered = $versions->get_versions();
$this->assertArrayHasKey( '1.0-dev', $registered );
$this->assertArrayHasKey( '1.0', $registered );
$this->assertCount( 2, $registered );
$this->assertEquals( 'callback_1_dot_0_dev', $registered['1.0-dev'] );
}
public function test_duplicate_version() {
$versions = new ActionScheduler_Versions();
$versions->register('1.0', 'callback_1_dot_0_a');
$versions->register('1.0', 'callback_1_dot_0_b');
$registered = $versions->get_versions();
$this->assertArrayHasKey( '1.0', $registered );
$this->assertCount( 1, $registered );
}
public function test_latest_version() {
$versions = new ActionScheduler_Versions();
$this->assertEquals('__return_null', $versions->latest_version_callback() );
$versions->register('1.2', 'callback_1_dot_2');
$versions->register('1.3', 'callback_1_dot_3');
$versions->register('1.0', 'callback_1_dot_0');
$this->assertEquals( '1.3', $versions->latest_version() );
$this->assertEquals( 'callback_1_dot_3', $versions->latest_version_callback() );
}
}