woocommerce-paypal-payments/tests/PHPUnit/AgenticCommerce/Ingestion/IngestionBatchProviderTest.php
Moritz Meißelbach 9590e0c298 test(AgenticCommerce): Add comprehensive test coverage for ingestion components
This commit adds unit tests for the Agentic Commerce ingestion functionality:
- Add tests for ProductsPayload class covering simple products, variable products, and edge cases
- Add tests for IngestionBatchProvider with various batch scenarios and priority handling
- Add tests for SyncJob including successful syncs, error handling, and metadata updates
- Add ProductsPayloadFactory to enable dependency injection in SyncJob
- Add ProductStatus stub for WooCommerce enum compatibility
- Update patchwork.json to support mocking of date functions in tests
2025-11-03 16:43:39 +01:00

358 lines
No EOL
10 KiB
PHP

<?php
declare( strict_types = 1 );
namespace WooCommerce\PayPalCommerce\AgenticCommerce\Ingestion;
use WooCommerce\PayPalCommerce\TestCase;
use Automattic\WooCommerce\Enums\ProductStatus;
use function Brain\Monkey\Functions\when;
/**
* @covers IngestionBatchProvider
*/
class IngestionBatchProviderTest extends TestCase {
/**
* @var int
*/
private $stale_timeout_days = 7;
/**
* @var array
*/
private $product_types = array( 'simple', 'variable' );
/**
* @var IngestionBatchProvider
*/
private $provider;
public function setUp(): void {
parent::setUp();
$this->provider = new IngestionBatchProvider(
$this->stale_timeout_days,
$this->product_types
);
// Mock WordPress date functions
when( 'gmdate' )->alias( function( $format, $timestamp = null ) {
if ( $timestamp === null ) {
$timestamp = time();
}
return gmdate( $format, $timestamp );
} );
when( 'strtotime' )->alias( 'strtotime' );
}
public function test_get_batch_returns_never_synced_products_first(): void {
// Arrange
$never_synced_ids = array( 1, 2, 3, 4, 5 );
$limit = 10;
// Mock wc_get_products calls
when( 'wc_get_products' )->alias( function( $args ) use ( $never_synced_ids ) {
// First call - products never synced
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_last_sync' &&
$args['meta_query'][0]['compare'] === 'NOT EXISTS' ) {
$this->assertEquals( ProductStatus::PUBLISH, $args['status'] );
$this->assertEquals( $this->product_types, $args['type'] );
$this->assertFalse( $args['downloadable'] );
$this->assertEquals( 10, $args['limit'] );
$this->assertEquals( 'ids', $args['return'] );
return $never_synced_ids;
}
// Second call - products needing sync
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_needs_sync' ) {
$this->assertEquals( 5, $args['limit'] ); // 10 - 5 already found
return array( 6, 7 );
}
// Third call - stale products
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_last_sync' &&
$args['meta_query'][0]['compare'] === '<' ) {
$this->assertEquals( 3, $args['limit'] ); // 10 - 7 already found
$this->assertEquals( 'DATETIME', $args['meta_query'][0]['type'] );
$this->assertEquals( 'meta_value', $args['orderby'] );
$this->assertEquals( 'ASC', $args['order'] );
$this->assertEquals( '_ppcp_agentic_last_sync', $args['meta_key'] );
return array( 8, 9, 10 );
}
return array();
} );
// Act
$result = $this->provider->get_batch( $limit );
// Assert
$this->assertEquals( array( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ), $result );
}
public function test_get_batch_respects_limit_with_never_synced_products(): void {
// Arrange
$never_synced_ids = array( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 );
$limit = 5;
when( 'wc_get_products' )->alias( function( $args ) use ( $never_synced_ids ) {
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_last_sync' &&
$args['meta_query'][0]['compare'] === 'NOT EXISTS' ) {
$this->assertEquals( 5, $args['limit'] );
return array_slice( $never_synced_ids, 0, 5 );
}
return array();
} );
// Act
$result = $this->provider->get_batch( $limit );
// Assert
$this->assertEquals( array( 1, 2, 3, 4, 5 ), $result );
$this->assertCount( 5, $result );
}
public function test_get_batch_returns_dirty_products_when_no_never_synced(): void {
// Arrange
$dirty_product_ids = array( 11, 12, 13 );
$limit = 5;
when( 'wc_get_products' )->alias( function( $args ) use ( $dirty_product_ids ) {
// First call - no never synced products
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_last_sync' &&
$args['meta_query'][0]['compare'] === 'NOT EXISTS' ) {
return array();
}
// Second call - products needing sync
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_needs_sync' ) {
$this->assertEquals( 5, $args['limit'] );
return $dirty_product_ids;
}
// Third call - stale products
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_last_sync' &&
$args['meta_query'][0]['compare'] === '<' ) {
$this->assertEquals( 2, $args['limit'] ); // 5 - 3 already found
return array( 14, 15 );
}
return array();
} );
// Act
$result = $this->provider->get_batch( $limit );
// Assert
$this->assertEquals( array( 11, 12, 13, 14, 15 ), $result );
}
public function test_get_batch_returns_stale_products_when_no_other_products(): void {
// Arrange
$stale_product_ids = array( 21, 22, 23, 24 );
$limit = 5;
when( 'wc_get_products' )->alias( function( $args ) use ( $stale_product_ids ) {
// First call - no never synced products
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_last_sync' &&
$args['meta_query'][0]['compare'] === 'NOT EXISTS' ) {
return array();
}
// Second call - no dirty products
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_needs_sync' ) {
return array();
}
// Third call - stale products
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_last_sync' &&
$args['meta_query'][0]['compare'] === '<' ) {
$this->assertEquals( 5, $args['limit'] );
// Verify stale date calculation
$expected_stale_date = gmdate( 'Y-m-d H:i:s', strtotime( '-7 days' ) );
$this->assertEquals( $expected_stale_date, $args['meta_query'][0]['value'] );
return $stale_product_ids;
}
return array();
} );
// Act
$result = $this->provider->get_batch( $limit );
// Assert
$this->assertEquals( $stale_product_ids, $result );
}
public function test_get_batch_returns_empty_array_when_no_products(): void {
// Arrange
when( 'wc_get_products' )->justReturn( array() );
// Act
$result = $this->provider->get_batch( 50 );
// Assert
$this->assertEquals( array(), $result );
}
public function test_get_batch_uses_correct_product_query_parameters(): void {
// Arrange
$limit = 50;
$call_count = 0;
when( 'wc_get_products' )->alias( function( $args ) use ( &$call_count ) {
$call_count++;
// Common assertions for all calls
$this->assertEquals( 'publish', $args['status'] );
$this->assertEquals( $this->product_types, $args['type'] );
$this->assertFalse( $args['downloadable'] );
$this->assertEquals( 'ids', $args['return'] );
// Return different results to trigger all three queries
if ( $call_count === 1 ) {
return array( 1, 2 );
} elseif ( $call_count === 2 ) {
return array( 3, 4 );
} else {
return array( 5, 6 );
}
} );
// Act
$result = $this->provider->get_batch( $limit );
// Assert
$this->assertEquals( 3, $call_count );
$this->assertEquals( array( 1, 2, 3, 4, 5, 6 ), $result );
}
public function test_get_batch_with_custom_stale_timeout(): void {
// Arrange
$custom_timeout_days = 30;
$custom_provider = new IngestionBatchProvider(
$custom_timeout_days,
$this->product_types
);
when( 'wc_get_products' )->alias( function( $args ) use ( $custom_timeout_days ) {
// Skip to stale products check
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_last_sync' &&
$args['meta_query'][0]['compare'] === '<' ) {
$expected_stale_date = gmdate( 'Y-m-d H:i:s', strtotime( '-30 days' ) );
$this->assertEquals( $expected_stale_date, $args['meta_query'][0]['value'] );
return array( 100, 101, 102 );
}
return array();
} );
// Act
$result = $custom_provider->get_batch( 10 );
// Assert
$this->assertContains( 100, $result );
$this->assertContains( 101, $result );
$this->assertContains( 102, $result );
}
public function test_get_batch_with_custom_product_types(): void {
// Arrange
$custom_types = array( 'simple', 'variable', 'grouped' );
$custom_provider = new IngestionBatchProvider(
$this->stale_timeout_days,
$custom_types
);
when( 'wc_get_products' )->alias( function( $args ) use ( $custom_types ) {
$this->assertEquals( $custom_types, $args['type'] );
return array( 1, 2, 3 );
} );
// Act
$result = $custom_provider->get_batch( 10 );
// Assert
$this->assertNotEmpty( $result );
}
public function test_get_batch_handles_mixed_results(): void {
// Arrange
$limit = 15;
when( 'wc_get_products' )->alias( function( $args ) {
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_last_sync' &&
$args['meta_query'][0]['compare'] === 'NOT EXISTS' ) {
return array( 1, 2, 3, 4, 5 );
}
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_needs_sync' ) {
$this->assertEquals( 10, $args['limit'] ); // 15 - 5
return array( 6, 7, 8, 9, 10 );
}
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_last_sync' &&
$args['meta_query'][0]['compare'] === '<' ) {
$this->assertEquals( 5, $args['limit'] ); // 15 - 10
return array( 11, 12, 13, 14, 15 );
}
return array();
} );
// Act
$result = $this->provider->get_batch( $limit );
// Assert
$this->assertCount( 15, $result );
$this->assertEquals( range( 1, 15 ), $result );
}
public function test_get_batch_stops_when_limit_reached_after_dirty_products(): void {
// Arrange
$limit = 7;
when( 'wc_get_products' )->alias( function( $args ) {
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_last_sync' &&
$args['meta_query'][0]['compare'] === 'NOT EXISTS' ) {
return array( 1, 2, 3 );
}
if ( isset( $args['meta_query'][0]['key'] ) &&
$args['meta_query'][0]['key'] === '_ppcp_agentic_needs_sync' ) {
return array( 4, 5, 6, 7 );
}
// This should not be called
$this->fail( 'Should not query for stale products when limit is reached' );
return array();
} );
// Act
$result = $this->provider->get_batch( $limit );
// Assert
$this->assertCount( 7, $result );
$this->assertEquals( array( 1, 2, 3, 4, 5, 6, 7 ), $result );
}
}