diff --git a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-system-status-tools-controller.php b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-system-status-tools-controller.php index 1cc3cceeaa8..2d7120d9068 100644 --- a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-system-status-tools-controller.php +++ b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-system-status-tools-controller.php @@ -55,7 +55,7 @@ class WC_Admin_REST_System_Status_Tools_Controller extends WC_REST_System_Status switch ( $tool ) { case 'rebuild_stats': - WC_Admin_Reports_Orders_Stats_Data_Store::queue_order_stats_repopulate_database(); + WC_Admin_Api_Init::regenerate_report_data(); $message = __( 'Rebuilding reports data in the background . . .', 'wc-admin' ); break; default: 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 b995d195428..fc86d08615d 100644 --- a/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php +++ b/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php @@ -12,6 +12,38 @@ defined( 'ABSPATH' ) || exit; */ class WC_Admin_Api_Init { + /** + * Action hook for reducing a range of batches down to single actions. + */ + const QUEUE_BATCH_ACTION = 'wc-admin_queue_batches'; + + /** + * Action hook for queuing an action after another is complete. + */ + const QUEUE_DEPEDENT_ACTION = 'wc-admin_queue_dependent_action'; + + /** + * Action hook for processing a batch of customers. + */ + const CUSTOMERS_BATCH_ACTION = 'wc-admin_process_customers_batch'; + + /** + * Action hook for processing a batch of orders. + */ + const ORDERS_BATCH_ACTION = 'wc-admin_process_orders_batch'; + + /** + * Action hook for initializing the orders lookup batch creation. + */ + const ORDERS_LOOKUP_BATCH_INIT = 'wc-admin_orders_lookup_batch_init'; + + /** + * Queue instance. + * + * @var WC_Queue_Interface + */ + protected static $queue = null; + /** * Boostrap REST API. */ @@ -30,9 +62,38 @@ class WC_Admin_Api_Init { // Initialize Orders data store class's static vars. add_action( 'woocommerce_after_register_post_type', array( 'WC_Admin_Api_Init', 'orders_data_store_init' ), 20 ); // Initialize Customers Report data store sync hooks. - // Note: we need to hook into 'wp' before `wc_current_user_is_active`. + // Note: we need to hook in before `wc_current_user_is_active`. // See: https://github.com/woocommerce/woocommerce/blob/942615101ba00c939c107c3a4820c3d466864872/includes/wc-user-functions.php#L749. - add_action( 'wp', array( 'WC_Admin_Api_Init', 'customers_report_data_store_init' ), 9 ); + add_action( 'wp_loaded', array( 'WC_Admin_Api_Init', 'customers_report_data_store_init' ) ); + + // Initialize scheduled action handlers. + add_action( self::QUEUE_BATCH_ACTION, array( __CLASS__, 'queue_batches' ), 10, 3 ); + add_action( self::QUEUE_DEPEDENT_ACTION, array( __CLASS__, 'queue_dependent_action' ), 10, 2 ); + add_action( self::CUSTOMERS_BATCH_ACTION, array( __CLASS__, 'customer_lookup_process_batch' ) ); + add_action( self::ORDERS_BATCH_ACTION, array( __CLASS__, 'orders_lookup_process_batch' ) ); + 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; } /** @@ -280,9 +341,9 @@ class WC_Admin_Api_Init { public static function regenerate_report_data() { // Add registered customers to the lookup table before updating order stats // so that the orders can be associated with the `customer_id` column. - self::customer_lookup_store_init(); - WC_Admin_Reports_Orders_Stats_Data_Store::queue_order_stats_repopulate_database(); - self::order_product_lookup_store_init(); + self::customer_lookup_batch_init(); + // Queue orders lookup to occur after customers lookup generation is done. + self::queue_dependent_action( self::ORDERS_LOOKUP_BATCH_INIT, self::CUSTOMERS_BATCH_ACTION ); } /** @@ -316,39 +377,54 @@ class WC_Admin_Api_Init { } /** - * Init orders product lookup store. - * - * @param WC_Background_Updater|null $updater Updater instance. - * @return bool + * Init order/product lookup tables update (in batches). */ - public static function order_product_lookup_store_init( $updater = null ) { - // TODO: this needs to be updated a bit, as it no longer runs as a part of WC_Install, there is no bg updater. - global $wpdb; + public static function orders_lookup_batch_init() { + $batch_size = self::get_batch_size( self::ORDERS_BATCH_ACTION ); + $order_query = new WC_Order_Query( + array( + 'return' => 'ids', + 'limit' => 1, + 'paginate' => true, + ) + ); + $result = $order_query->get_orders(); - $orders = get_transient( 'wc_update_350_all_orders' ); - if ( false === $orders ) { - $orders = wc_get_orders( - array( - 'limit' => -1, - 'return' => 'ids', - ) - ); - set_transient( 'wc_update_350_all_orders', $orders, DAY_IN_SECONDS ); + if ( 0 === $result->total ) { + return; } - // Process orders until close to running out of memory timeouts on large sites then requeue. - foreach ( $orders as $order_id ) { + $num_batches = ceil( $result->total / $batch_size ); + + self::queue_batches( 1, $num_batches, self::ORDERS_BATCH_ACTION ); + } + + /** + * Process a batch of orders to update (stats and products). + * + * @param int $batch_number Batch number to process (essentially a query page number). + * @return void + */ + public static function orders_lookup_process_batch( $batch_number ) { + $batch_size = self::get_batch_size( self::ORDERS_BATCH_ACTION ); + $order_query = new WC_Order_Query( + array( + 'return' => 'ids', + 'limit' => $batch_size, + 'page' => $batch_number, + 'orderby' => 'ID', + 'order' => 'ASC', + ) + ); + $order_ids = $order_query->get_orders(); + + foreach ( $order_ids as $order_id ) { + // TODO: schedule single order update if this fails? + WC_Admin_Reports_Orders_Stats_Data_Store::sync_order( $order_id ); WC_Admin_Reports_Products_Data_Store::sync_order_products( $order_id ); - // Pop the order ID from the array for updating the transient later should we near memory exhaustion. - unset( $orders[ $order_id ] ); - if ( $updater instanceof WC_Background_Updater && $updater->is_memory_exceeded() ) { - // Update the transient for the next run to avoid processing the same orders again. - set_transient( 'wc_update_350_all_orders', $orders, DAY_IN_SECONDS ); - return true; - } + WC_Admin_Reports_Coupons_Data_Store::sync_order_coupons( $order_id ); + WC_Admin_Reports_Taxes_Data_Store::sync_order_taxes( $order_id ); } - - return true; } /** @@ -359,49 +435,144 @@ class WC_Admin_Api_Init { } /** - * Init customer lookup store. + * Returns the batch size for regenerating reports. + * Note: can differ per batch action. * - * @param WC_Background_Updater|null $updater Updater instance. - * @return bool + * @param string $action Single batch action name. + * @return int Batch size. */ - public static function customer_lookup_store_init( $updater = null ) { - // TODO: this needs to be updated a bit, as it no longer runs as a part of WC_Install, there is no bg updater. - global $wpdb; + public static function get_batch_size( $action ) { + $batch_sizes = array( + self::QUEUE_BATCH_ACTION => 100, + self::CUSTOMERS_BATCH_ACTION => 25, + self::ORDERS_BATCH_ACTION => 10, + ); + $batch_size = isset( $batch_sizes[ $action ] ) ? $batch_sizes[ $action ] : 25; - // Backfill customer lookup table with registered customers. - $customer_ids = get_transient( 'wc_update_350_all_customers' ); + /** + * Filter the batch size for regenerating a report table. + * + * @param int $batch_size Batch size. + * @param string $action Batch action name. + */ + return apply_filters( 'wc_admin_report_regenerate_batch_size', $batch_size, $action ); + } - if ( false === $customer_ids ) { - $customer_query = new WP_User_Query( - array( - 'fields' => 'ID', - 'role' => 'customer', - 'number' => -1, - ) + /** + * Queue a large number of batch jobs, respecting the batch size limit. + * Reduces a range of batches down to "single batch" jobs. + * + * @param int $range_start Starting batch number. + * @param int $range_end Ending batch number. + * @param string $single_batch_action Action to schedule for a single batch. + * @return void + */ + 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 ); + $action_timestamp = time() + 5; + + if ( $range_size > $batch_size ) { + // If the current batch range is larger than a single batch, + // split the range into $queue_batch_size chunks. + $chunk_size = ceil( $range_size / $batch_size ); + + for ( $i = 0; $i < $batch_size; $i++ ) { + $batch_start = $range_start + ( $i * $chunk_size ); + $batch_end = min( $range_end, $range_start + ( $chunk_size * ( $i + 1 ) ) - 1 ); + + self::queue()->schedule_single( + $action_timestamp, + self::QUEUE_BATCH_ACTION, + array( $batch_start, $batch_end, $single_batch_action ) + ); + } + } else { + // Otherwise, queue the single batches. + for ( $i = $range_start; $i <= $range_end; $i++ ) { + self::queue()->schedule_single( $action_timestamp, $single_batch_action, array( $i ) ); + } + } + } + + /** + * Queue an action to run after another. + * + * @param string $action Action to run after prerequisite. + * @param string $prerequisite_action Prerequisite action. + */ + public static function queue_dependent_action( $action, $prerequisite_action ) { + $blocking_jobs = self::queue()->search( + array( + 'status' => 'pending', + 'orderby' => 'date', + 'order' => 'DESC', + 'per_page' => 1, + 'claimed' => false, + 'search' => $prerequisite_action, // search is used instead of hook to find queued batch creation. + ) + ); + + if ( $blocking_jobs ) { + $blocking_job = current( $blocking_jobs ); + $after_blocking_job = $blocking_job->get_schedule()->next()->getTimestamp() + 5; + + self::queue()->schedule_single( + $after_blocking_job, + self::QUEUE_DEPEDENT_ACTION, + array( $action, $prerequisite_action ) ); + } else { + self::queue()->schedule_single( time() + 5, $action ); + } + } - $customer_ids = $customer_query->get_results(); + /** + * Init customer lookup table update (in batches). + */ + public static function customer_lookup_batch_init() { + $batch_size = self::get_batch_size( self::CUSTOMERS_BATCH_ACTION ); + $customer_query = new WP_User_Query( + array( + 'fields' => 'ID', + 'number' => 1, + ) + ); + $total_customers = $customer_query->get_total(); - set_transient( 'wc_update_350_all_customers', $customer_ids, DAY_IN_SECONDS ); + if ( 0 === $total_customers ) { + return; } - // Process customers until close to running out of memory timeouts on large sites then requeue. + $num_batches = ceil( $total_customers / $batch_size ); + + self::queue_batches( 1, $num_batches, self::CUSTOMERS_BATCH_ACTION ); + } + + /** + * Process a batch of customers to update. + * + * @param int $batch_number Batch number to process (essentially a query page number). + * @return void + */ + public static function customer_lookup_process_batch( $batch_number ) { + $batch_size = self::get_batch_size( self::CUSTOMERS_BATCH_ACTION ); + $customer_query = new WP_User_Query( + array( + 'fields' => 'ID', + 'orderby' => 'ID', + 'order' => 'ASC', + 'number' => $batch_size, + 'paged' => $batch_number, + ) + ); + + $customer_ids = $customer_query->get_results(); + foreach ( $customer_ids as $customer_id ) { - $result = WC_Admin_Reports_Customers_Data_Store::update_registered_customer( $customer_id ); - - if ( $result ) { - // Pop the customer ID from the array for updating the transient later should we near memory exhaustion. - unset( $customer_ids[ $customer_id ] ); - } - - if ( $updater instanceof WC_Background_Updater && $updater->is_memory_exceeded() ) { - // Update the transient for the next run to avoid processing the same orders again. - set_transient( 'wc_update_350_all_customers', $customer_ids, DAY_IN_SECONDS ); - return true; - } + // TODO: schedule single customer update if this fails? + WC_Admin_Reports_Customers_Data_Store::update_registered_customer( $customer_id ); } - - return true; } /** @@ -583,8 +754,7 @@ class WC_Admin_Api_Init { self::create_db_tables(); // Initialize report tables. - add_action( 'woocommerce_after_register_post_type', array( 'WC_Admin_Api_Init', 'order_product_lookup_store_init' ), 20 ); - add_action( 'woocommerce_after_register_post_type', array( 'WC_Admin_Api_Init', 'customer_lookup_store_init' ), 20 ); + add_action( 'woocommerce_after_register_post_type', array( __CLASS__, 'regenerate_report_data' ), 20 ); } } diff --git a/plugins/woocommerce-admin/includes/class-wc-admin-order-stats-background-process.php b/plugins/woocommerce-admin/includes/class-wc-admin-order-stats-background-process.php deleted file mode 100644 index 46f76aef209..00000000000 --- a/plugins/woocommerce-admin/includes/class-wc-admin-order-stats-background-process.php +++ /dev/null @@ -1,77 +0,0 @@ -prefix = 'wp_' . get_current_blog_id(); - $this->action = 'wc_order_stats'; - parent::__construct(); - } - - /** - * Push to queue without scheduling duplicate recalculation events. - * Overrides WC_Background_Process::push_to_queue. - * - * @param integer $data Timestamp of hour to generate stats. - */ - public function push_to_queue( $data ) { - $data = absint( $data ); - if ( ! in_array( $data, $this->data, true ) ) { - $this->data[] = $data; - } - - return $this; - } - - /** - * Dispatch but only if there is data to update. - * Overrides WC_Background_Process::dispatch. - */ - public function dispatch() { - if ( ! $this->data ) { - return false; - } - - return parent::dispatch(); - } - - /** - * Code to execute for each item in the queue - * - * @param string $item Queue item to iterate over. - * @return bool - */ - protected function task( $item ) { - if ( ! $item ) { - return false; - } - - $order = wc_get_order( $item ); - if ( ! $order ) { - return false; - } - - WC_Admin_Reports_Orders_Stats_Data_Store::update( $order ); - return false; - } -} diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-stats-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-stats-data-store.php index ddaab352d8e..711d48362ab 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-stats-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-stats-data-store.php @@ -7,10 +7,6 @@ defined( 'ABSPATH' ) || exit; -if ( ! class_exists( 'WC_Admin_Order_Stats_Background_Process', false ) ) { - include_once WC_ADMIN_ABSPATH . '/includes/class-wc-admin-order-stats-background-process.php'; -} - /** * WC_Admin_Reports_Orders_Stats_Data_Store. * @@ -71,22 +67,6 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto 'num_new_customers' => 'SUM(returning_customer = 0) AS num_new_customers', ); - /** - * Background process to populate order stats. - * - * @var WC_Admin_Order_Stats_Background_Process - */ - protected static $background_process; - - /** - * Constructor. - */ - public function __construct() { - if ( ! self::$background_process ) { - self::$background_process = new WC_Admin_Order_Stats_Background_Process(); - } - } - /** * Set up all the hooks for maintaining and populating table data. */ @@ -96,10 +76,6 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto add_action( 'clean_post_cache', array( __CLASS__, 'sync_order' ) ); add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order' ) ); add_action( 'woocommerce_refund_deleted', array( __CLASS__, 'sync_on_refund_delete' ), 10, 2 ); - - if ( ! self::$background_process ) { - self::$background_process = new WC_Admin_Order_Stats_Background_Process(); - } } /** @@ -373,31 +349,6 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto ); // WPCS: cache ok, DB call ok, unprepared SQL ok. } - /** - * Queue a background process that will repopulate the entire orders stats database. - * - * @todo Make this work on large DBs. - */ - public static function queue_order_stats_repopulate_database() { - - // This needs to be updated to work in batches instead of getting all orders, as - // that will not work well on DBs with more than a few hundred orders. - $order_ids = wc_get_orders( - array( - 'limit' => -1, - 'type' => 'shop_order', - 'return' => 'ids', - ) - ); - - foreach ( $order_ids as $id ) { - self::$background_process->push_to_queue( $id ); - } - - self::$background_process->save(); - self::$background_process->dispatch(); - } - /** * Add order information to the lookup table when orders are created or modified. * diff --git a/plugins/woocommerce-admin/tests/api/reports-customers.php b/plugins/woocommerce-admin/tests/api/reports-customers.php index dfd8a7b3d3d..63e00d644cd 100644 --- a/plugins/woocommerce-admin/tests/api/reports-customers.php +++ b/plugins/woocommerce-admin/tests/api/reports-customers.php @@ -122,10 +122,6 @@ class WC_Tests_API_Reports_Customers extends WC_REST_Unit_Test_Case { $test_customers[] = WC_Helper_Customer::create_customer( "customer{$i}", 'password', "customer{$i}@example.com" ); } - // Initialize the report lookup table. - delete_transient( 'wc_update_350_all_customers' ); - WC_Admin_Api_Init::customer_lookup_store_init(); - // Create a test product for use in an order. $product = new WC_Product_Simple(); $product->set_name( 'Test Product' ); diff --git a/plugins/woocommerce-admin/tests/api/reports-orders.php b/plugins/woocommerce-admin/tests/api/reports-orders.php index 6e1e798b174..c625473eef4 100644 --- a/plugins/woocommerce-admin/tests/api/reports-orders.php +++ b/plugins/woocommerce-admin/tests/api/reports-orders.php @@ -67,6 +67,8 @@ class WC_Tests_API_Reports_Orders extends WC_REST_Unit_Test_Case { $order->set_total( 100 ); // $25 x 4. $order->save(); + $expected_customer_id = WC_Admin_Reports_Customers_Data_Store::get_customer_id_by_user_id( 1 ); + $response = $this->server->dispatch( new WP_REST_Request( 'GET', $this->endpoint ) ); $reports = $response->get_data(); @@ -77,7 +79,7 @@ class WC_Tests_API_Reports_Orders extends WC_REST_Unit_Test_Case { $this->assertEquals( $order->get_id(), $order_report['order_id'] ); $this->assertEquals( date( 'Y-m-d H:i:s', $order->get_date_created()->getTimestamp() ), $order_report['date_created'] ); - $this->assertEquals( 0, $order_report['customer_id'] ); // @TODO: This should be 1, but customer_id is returning 0 in lookup table. + $this->assertEquals( $expected_customer_id, $order_report['customer_id'] ); $this->assertEquals( 4, $order_report['num_items_sold'] ); $this->assertEquals( 90.0, $order_report['net_total'] ); // 25 x 4 - 10 (shipping) $this->assertEquals( 'new', $order_report['customer_type'] ); 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 ); + } +} diff --git a/plugins/woocommerce-admin/tests/bootstrap.php b/plugins/woocommerce-admin/tests/bootstrap.php index 0128f58c4b9..616c248cb18 100755 --- a/plugins/woocommerce-admin/tests/bootstrap.php +++ b/plugins/woocommerce-admin/tests/bootstrap.php @@ -114,3 +114,4 @@ wc_test_includes(); // Include wc-admin helpers. require_once dirname( __FILE__ ) . '/framework/helpers/class-wc-helper-reports.php'; require_once dirname( __FILE__ ) . '/framework/helpers/class-wc-helper-admin-notes.php'; +require_once dirname( __FILE__ ) . '/framework/helpers/class-wc-test-action-queue.php'; diff --git a/plugins/woocommerce-admin/tests/framework/helpers/class-wc-test-action-queue.php b/plugins/woocommerce-admin/tests/framework/helpers/class-wc-test-action-queue.php new file mode 100644 index 00000000000..dd2ddb0ad05 --- /dev/null +++ b/plugins/woocommerce-admin/tests/framework/helpers/class-wc-test-action-queue.php @@ -0,0 +1,34 @@ +actions[] = compact( 'timestamp', 'hook', 'args', 'group' ); + return true; + } +}