Commit c6c720103c7 for woocommerce

commit c6c720103c7b9192f36bc83d7f4101be0cee6a2b
Author: Vlad Olaru <vlad.olaru@automattic.com>
Date:   Wed Oct 7 14:16:46 2026 +0300

    [tests] Stop Analytics report fixtures relying on SQL truncation (#68921)

    * test(analytics): Stamp the truncated status in report fixtures

    Two Analytics report data-store tests register an order status longer
    than the 20-character status column and assert how the reports treat
    the truncated value that ends up stored. They built that fixture by
    calling set_status() with the full status and relying on the database
    to shorten it on the way in.

    Nothing guarantees that. WooCommerce sends the full value in a raw
    query, so whether it is stored truncated or rejected outright depends
    on the server's SQL mode. Under STRICT_TRANS_TABLES the write fails
    with "Data too long for column 'status'", the order keeps the status
    it already had, and the assertions then run against an order that
    never entered the state under test. Forcing that mode locally fails
    two of the three long-status titles; the third passes only because it
    expects a count of zero either way.

    Write the truncated status straight into whichever table backs orders
    and drop the order caches, so the fixture holds the same value in
    every environment.

    The trade-off is that the status no longer arrives through the order
    data store. Neither test now covers how
    Abstract_WC_Order_Data_Store_CPT::get_post_status() produces the
    truncated value, only how the reports read it back, and the
    expectation for that method's deprecation notice goes with it. What
    these titles exist to check is the report queries, which is
    unaffected.

    Split out of #68626 at review request.

    Refs TESTOPS-288
    Refs #68046

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    * test(analytics): Clear the HPOS order cache in report fixtures

    The long-status report fixtures write the truncated status straight
    into the orders table, which skips the data store's own cache
    invalidation. They drop the request-level order cache, but not the
    HPOS datastore cache, so with woocommerce_hpos_datastore_caching_enabled
    on, the reload and the report sync still read the old status. Forcing
    the flag on with HPOS enabled fails both titles ("Failed asserting
    that 0 is identical to 2" and "Failed asserting that false is true").
    The flag ships off, so CI passes today, but the fixtures should not
    depend on it staying off.

    Clear the order from OrdersTableDataStore right after the direct
    write, next to where the CPT branch already calls clean_post_cache().

    Also unregister the orders stats test's custom post status in
    tearDown() instead of at the end of the test body, so a failed
    assertion no longer leaks it into later tests. The trailing
    remove_filter() goes too: the base test case already restores hooks.

    Refs TESTOPS-288

    ---------

    Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

diff --git a/plugins/woocommerce/changelog/testops-288-strict-sql-report-fixtures b/plugins/woocommerce/changelog/testops-288-strict-sql-report-fixtures
new file mode 100644
index 00000000000..8d122283c76
--- /dev/null
+++ b/plugins/woocommerce/changelog/testops-288-strict-sql-report-fixtures
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+Comment: Build the long-custom-status fixture in two Analytics report data-store tests by writing the truncated status directly, instead of depending on the database to truncate it; test-only change, no production code touched.
+
diff --git a/plugins/woocommerce/tests/php/src/Admin/API/Reports/Orders/Stats/DataStoreTest.php b/plugins/woocommerce/tests/php/src/Admin/API/Reports/Orders/Stats/DataStoreTest.php
index e76ec0062da..614eae57863 100644
--- a/plugins/woocommerce/tests/php/src/Admin/API/Reports/Orders/Stats/DataStoreTest.php
+++ b/plugins/woocommerce/tests/php/src/Admin/API/Reports/Orders/Stats/DataStoreTest.php
@@ -6,6 +6,7 @@ namespace Automattic\WooCommerce\Tests\Admin\API\Reports\Orders\Stats;
 use Automattic\WooCommerce\Admin\API\Reports\Orders\Stats\DataStore as OrdersStatsDataStore;
 use Automattic\WooCommerce\Caches\OrderCache;
 use Automattic\WooCommerce\Internal\Admin\Schedulers\OrdersScheduler;
+use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
 use Automattic\WooCommerce\Utilities\OrderUtil;
 use WC_Helper_Order;
 use WC_Unit_Test_Case;
@@ -30,6 +31,13 @@ class DataStoreTest extends WC_Unit_Test_Case {
 	 */
 	private $previous_old_full_refund_flag;

+	/**
+	 * Post status registered by a test, unregistered in tearDown() so a failed assertion does not leak it.
+	 *
+	 * @var string|null
+	 */
+	private $registered_post_status = null;
+
 	/**
 	 * Set up test fixtures.
 	 */
@@ -53,6 +61,10 @@ class DataStoreTest extends WC_Unit_Test_Case {
 		} else {
 			delete_option( 'woocommerce_analytics_uses_old_full_refund_data' );
 		}
+		if ( null !== $this->registered_post_status ) {
+			unset( $GLOBALS['wp_post_statuses'][ $this->registered_post_status ] );
+			$this->registered_post_status = null;
+		}
 		parent::tearDown();
 	}

@@ -570,8 +582,9 @@ class DataStoreTest extends WC_Unit_Test_Case {
 	public function test_returning_customer_recalculated_for_long_excluded_status(): void {
 		global $wpdb;

-		$long_status = 'competition-completed';
-		register_post_status( 'wc-' . $long_status, array( 'public' => true ) );
+		$long_status                  = 'competition-completed';
+		$this->registered_post_status = 'wc-' . $long_status;
+		register_post_status( $this->registered_post_status, array( 'public' => true ) );
 		$add_status = function ( $statuses ) use ( $long_status ) {
 			$statuses[ 'wc-' . $long_status ] = 'Competition Completed';
 			return $statuses;
@@ -602,11 +615,34 @@ class DataStoreTest extends WC_Unit_Test_Case {
 		$this->assertSame( '0', $returning_flag( $order_1->get_id() ), 'Oldest order should start as the non-returning first order.' );
 		$this->assertSame( '1', $returning_flag( $order_2->get_id() ), 'Second order should start as returning.' );

-		// Core warns when saving a status longer than the 20-char column; that
-		// truncated storage is the exact scenario under test.
-		$this->setExpectedIncorrectUsage( 'Abstract_WC_Order_Data_Store_CPT::get_post_status' );
-		$order_1->set_status( $long_status );
-		$order_1->save();
+		// Saving the long status stores nothing: WordPress refuses to shorten an
+		// overlength value for the posts table, and the orders table only keeps a
+		// truncated one while strict SQL mode is off. Write the truncated status
+		// the reports are meant to read.
+		$truncated_status = mb_substr( 'wc-' . $long_status, 0, 20 );
+		if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
+			$wpdb->update(
+				$wpdb->prefix . 'wc_orders',
+				array( 'status' => $truncated_status ),
+				array( 'id' => $order_1->get_id() ),
+				array( '%s' ),
+				array( '%d' )
+			);
+			wc_get_container()->get( OrdersTableDataStore::class )->clear_cached_data( array( $order_1->get_id() ) );
+		} else {
+			$wpdb->update(
+				$wpdb->posts,
+				array( 'post_status' => $truncated_status ),
+				array( 'ID' => $order_1->get_id() ),
+				array( '%s' ),
+				array( '%d' )
+			);
+			clean_post_cache( $order_1->get_id() );
+		}
+
+		if ( OrderUtil::orders_cache_usage_is_enabled() ) {
+			wc_get_container()->get( OrderCache::class )->remove( $order_1->get_id() );
+		}

 		// Reload so the order reports the truncated status actually stored in the database.
 		$order_1 = wc_get_order( $order_1->get_id() );
@@ -620,8 +656,5 @@ class DataStoreTest extends WC_Unit_Test_Case {
 			$returning_flag( $order_2->get_id() ),
 			'The next oldest order should be reassigned as the customer\'s first order.'
 		);
-
-		remove_filter( 'wc_order_statuses', $add_status );
-		unset( $GLOBALS['wp_post_statuses'][ 'wc-' . $long_status ] );
 	}
 }
diff --git a/plugins/woocommerce/tests/php/src/Admin/API/Reports/Products/DataStoreTest.php b/plugins/woocommerce/tests/php/src/Admin/API/Reports/Products/DataStoreTest.php
index 8b54f8a9670..ed121a03b53 100644
--- a/plugins/woocommerce/tests/php/src/Admin/API/Reports/Products/DataStoreTest.php
+++ b/plugins/woocommerce/tests/php/src/Admin/API/Reports/Products/DataStoreTest.php
@@ -6,6 +6,9 @@ namespace Automattic\WooCommerce\Tests\Admin\API\Reports\Products;
 use Automattic\WooCommerce\Admin\API\Reports\Cache;
 use Automattic\WooCommerce\Admin\API\Reports\Orders\Stats\DataStore as OrdersStatsDataStore;
 use Automattic\WooCommerce\Admin\API\Reports\Products\DataStore as ProductsDataStore;
+use Automattic\WooCommerce\Caches\OrderCache;
+use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
+use Automattic\WooCommerce\Utilities\OrderUtil;
 use WC_Helper_Product;
 use WC_Unit_Test_Case;

@@ -57,17 +60,43 @@ class DataStoreTest extends WC_Unit_Test_Case {
 	 * @return int Product ID.
 	 */
 	private function create_synced_custom_status_order() {
-		// Core warns when saving a status longer than the 20-char column; that
-		// truncated storage is the exact scenario under test.
-		$this->setExpectedIncorrectUsage( 'Abstract_WC_Order_Data_Store_CPT::get_post_status' );
+		global $wpdb;

 		$product = WC_Helper_Product::create_simple_product();
 		$order   = wc_create_order();
 		$order->add_product( $product, 2 );
 		$order->calculate_totals();
-		$order->set_status( $this->long_status );
 		$order->save();

+		// Saving the long status stores nothing: WordPress refuses to shorten an
+		// overlength value for the posts table, and the orders table only keeps a
+		// truncated one while strict SQL mode is off. Write the truncated status
+		// the reports are meant to read.
+		$truncated_status = mb_substr( 'wc-' . $this->long_status, 0, 20 );
+		if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
+			$wpdb->update(
+				$wpdb->prefix . 'wc_orders',
+				array( 'status' => $truncated_status ),
+				array( 'id' => $order->get_id() ),
+				array( '%s' ),
+				array( '%d' )
+			);
+			wc_get_container()->get( OrdersTableDataStore::class )->clear_cached_data( array( $order->get_id() ) );
+		} else {
+			$wpdb->update(
+				$wpdb->posts,
+				array( 'post_status' => $truncated_status ),
+				array( 'ID' => $order->get_id() ),
+				array( '%s' ),
+				array( '%d' )
+			);
+			clean_post_cache( $order->get_id() );
+		}
+
+		if ( OrderUtil::orders_cache_usage_is_enabled() ) {
+			wc_get_container()->get( OrderCache::class )->remove( $order->get_id() );
+		}
+
 		OrdersStatsDataStore::sync_order( $order->get_id() );
 		ProductsDataStore::sync_order_products( $order->get_id() );