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,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 );
}
}