From 5c6174066ec78118e8922088adc46e5a767525ee Mon Sep 17 00:00:00 2001 From: Jeff Stieler Date: Fri, 11 Jan 2019 18:20:08 -0700 Subject: [PATCH] Add tests for report regeneration batch queuing methods. --- .../includes/class-wc-admin-api-init.php | 41 +++- .../woocommerce-admin/tests/batch-queue.php | 184 ++++++++++++++++++ 2 files changed, 218 insertions(+), 7 deletions(-) create mode 100644 plugins/woocommerce-admin/tests/batch-queue.php diff --git a/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php b/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php index b309054a3c3..f3d2d647b92 100644 --- a/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php +++ b/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php @@ -37,6 +37,13 @@ class WC_Admin_Api_Init { */ const ORDERS_LOOKUP_BATCH_INIT = 'wc-admin_orders_lookup_batch_init'; + /** + * Queue instance. + * + * @var WC_Queue_Interface + */ + protected static $queue = null; + /** * Boostrap REST API. */ @@ -67,6 +74,28 @@ class WC_Admin_Api_Init { add_action( self::ORDERS_LOOKUP_BATCH_INIT, array( __CLASS__, 'orders_lookup_batch_init' ) ); } + /** + * Get queue instance. + * + * @return WC_Queue_Interface + */ + public static function queue() { + if ( is_null( self::$queue ) ) { + self::$queue = WC()->queue(); + } + + return self::$queue; + } + + /** + * Set queue instance. + * + * @param WC_Queue_Interface $queue Queue instance. + */ + public static function set_queue( $queue ) { + self::$queue = $queue; + } + /** * Init classes. */ @@ -434,7 +463,6 @@ class WC_Admin_Api_Init { public static function queue_batches( $range_start, $range_end, $single_batch_action ) { $batch_size = self::get_batch_size( self::QUEUE_BATCH_ACTION ); $range_size = 1 + ( $range_end - $range_start ); - $queue = WC()->queue(); $schedule = time() + 5; if ( $range_size > $batch_size ) { @@ -446,7 +474,7 @@ class WC_Admin_Api_Init { $batch_start = $range_start + ( $i * $chunk_size ); $batch_end = min( $range_end, $range_start + ( $chunk_size * ( $i + 1 ) ) - 1 ); - $queue->schedule_single( + self::queue()->schedule_single( $schedule, self::QUEUE_BATCH_ACTION, array( $batch_start, $batch_end, $single_batch_action ) @@ -455,7 +483,7 @@ class WC_Admin_Api_Init { } else { // Otherwise, queue the single batches. for ( $i = $range_start; $i <= $range_end; $i++ ) { - $queue->schedule_single( $schedule, $single_batch_action, array( $i ) ); + self::queue()->schedule_single( $schedule, $single_batch_action, array( $i ) ); } } } @@ -467,8 +495,7 @@ class WC_Admin_Api_Init { * @param string $prerequisite_action Prerequisite action. */ public static function queue_dependent_action( $action, $prerequisite_action ) { - $queue = WC()->queue(); - $blocking_jobs = $queue->search( + $blocking_jobs = self::queue()->search( array( 'status' => 'pending', 'orderby' => 'date', @@ -483,13 +510,13 @@ class WC_Admin_Api_Init { $blocking_job = current( $blocking_jobs ); $after_blocking_job = $blocking_job->get_schedule()->next()->getTimestamp() + 5; - $queue->schedule_single( + self::queue()->schedule_single( $after_blocking_job, self::QUEUE_DEPEDENT_ACTION, array( $action, $prerequisite_action ) ); } else { - $queue->schedule_single( time() + 5, $action ); + self::queue()->schedule_single( time() + 5, $action ); } } diff --git a/plugins/woocommerce-admin/tests/batch-queue.php b/plugins/woocommerce-admin/tests/batch-queue.php new file mode 100644 index 00000000000..d8711afdc60 --- /dev/null +++ b/plugins/woocommerce-admin/tests/batch-queue.php @@ -0,0 +1,184 @@ +queue_batch_size; + case WC_Admin_Api_Init::CUSTOMERS_BATCH_ACTION: + return $this->customers_batch_size; + case WC_Admin_Api_Init::ORDERS_BATCH_ACTION: + return $this->orders_batch_size; + default: + return 1; + } + } + + /** + * Set up. + */ + public function setUp() { + parent::setUp(); + $this->queue = new WC_Admin_Test_Action_Queue(); + WC_Admin_Api_Init::set_queue( $this->queue ); + add_filter( 'wc_admin_report_regenerate_batch_size', array( $this, 'filter_batch_size' ), 10, 2 ); + } + + /** + * Tear down. + */ + public function tearDown() { + parent::tearDown(); + WC_Admin_Api_Init::set_queue( null ); + $this->queue->actions = array(); + remove_filter( 'wc_admin_report_regenerate_batch_size', array( $this, 'filter_batch_size' ), 10, 2 ); + } + + /** + * Test that large batches get split properly. + */ + public function test_queue_batches_splits_into_batches_correctly() { + $num_customers = 1234; // 1234 / 5 = 247 batches + $num_batches = ceil( $num_customers / $this->customers_batch_size ); + + WC_Admin_Api_Init::queue_batches( 1, $num_batches, WC_Admin_Api_Init::CUSTOMERS_BATCH_ACTION ); + + $this->assertCount( $this->queue_batch_size, $this->queue->actions ); + $this->assertArraySubset( + array( + 'hook' => WC_Admin_Api_Init::QUEUE_BATCH_ACTION, + 'args' => array( 1, 25, WC_Admin_Api_Init::CUSTOMERS_BATCH_ACTION ), + ), + $this->queue->actions[0] + ); + $this->assertArraySubset( + array( + 'hook' => WC_Admin_Api_Init::QUEUE_BATCH_ACTION, + 'args' => array( 226, 247, WC_Admin_Api_Init::CUSTOMERS_BATCH_ACTION ), + ), + $this->queue->actions[ $this->queue_batch_size - 1 ] + ); + } + + /** + * Test that small enough batches have their "single" action queued. + */ + public function test_queue_batches_schedules_single_actions() { + $num_customers = 45; // 45 / 5 = 9 batches (which is less than the batch queue size) + $num_batches = ceil( $num_customers / $this->customers_batch_size ); + + WC_Admin_Api_Init::queue_batches( 1, $num_batches, WC_Admin_Api_Init::CUSTOMERS_BATCH_ACTION ); + + $this->assertCount( 9, $this->queue->actions ); + $this->assertArraySubset( + array( + 'hook' => WC_Admin_Api_Init::CUSTOMERS_BATCH_ACTION, + 'args' => array( 1 ), + ), + $this->queue->actions[0] + ); + $this->assertArraySubset( + array( + 'hook' => WC_Admin_Api_Init::CUSTOMERS_BATCH_ACTION, + 'args' => array( 9 ), + ), + $this->queue->actions[8] + ); + } + + /** + * Test that batch dependencies work. + */ + public function test_queue_dependent_action() { + // reset back to using a real queue. + WC_Admin_Api_Init::set_queue( null ); + + // insert a blocking job. + WC_Admin_Api_Init::queue()->schedule_single( time(), 'blocking_job', array( 'stuff' ) ); + // queue an action that depends on blocking job. + WC_Admin_Api_Init::queue_dependent_action( 'dependent_action', 'blocking_job' ); + // verify that the action was properly blocked. + $this->assertEmpty( + WC_Admin_Api_Init::queue()->search( + array( + 'hook' => 'dependent_action', + ) + ) + ); + // verify that a follow up action was queued. + $this->assertCount( + 1, + WC_Admin_Api_Init::queue()->search( + array( + 'hook' => WC_Admin_Api_Init::QUEUE_DEPEDENT_ACTION, + 'args' => array( 'dependent_action', 'blocking_job' ), + ) + ) + ); + + // queue an action that isn't blocked. + WC_Admin_Api_Init::queue_dependent_action( 'another_dependent_action', 'nonexistant_blocking_job' ); + // verify that the dependent action was queued. + $this->assertCount( + 1, + WC_Admin_Api_Init::queue()->search( + array( + 'hook' => 'another_dependent_action', + ) + ) + ); + // verify that no follow up action was queued. + $this->assertEmpty( + WC_Admin_Api_Init::queue()->search( + array( + 'hook' => WC_Admin_Api_Init::QUEUE_DEPEDENT_ACTION, + 'args' => array( 'another_dependent_action', 'nonexistant_blocking_job' ), + ) + ) + ); + + // clean up. + WC_Admin_Api_Init::queue()->cancel_all( 'another_dependent_action' ); + WC_Admin_Api_Init::queue()->cancel_all( WC_Admin_Api_Init::QUEUE_DEPEDENT_ACTION ); + } +}