Commit e50063a16fe for woocommerce

commit e50063a16fe61e290b9ba80b68a85d164a11a084
Author: Vlad Olaru <vlad.olaru@automattic.com>
Date:   Wed Nov 4 11:49:12 2026 +0200

    [tests] Fix HPOS PHPUnit fixture transaction boundaries (#70500)

    * test: Fix HPOS cleanup before transaction rollback

    LegacyDataCleanupTests restored its HPOS state after the parent teardown
    had rolled back the database transaction. The option cache could then
    hide the restored database value and leave cleanup in an inconsistent
    state across repeated tests.

    Run the existing HPOS cleanup before the rollback and guarantee the
    parent teardown with finally, including when fixture cleanup fails.

    * test: Prepare HPOS tables before test transactions

    Five test classes call setup_cot() from per-test setup, repeatedly
    recreating permanent HPOS tables after the transaction has started.
    Those DDL statements can implicitly commit fixture state.

    Use the existing class-level setup_cot_tables() pattern instead. Keep
    each test's temporary-table filters and HPOS toggle sequence, and remove
    the five obsolete DDL guard exemptions. Test bodies, providers and
    assertions stay unchanged.

    * chore: Add changelog for HPOS fixture cleanup

    Record the test-only fixture and cleanup changes without adding a merchant-facing release note.

    * test: Remove repeated HPOS fixture enables

    Inlining setup_cot() exposed an existing second enable in EditLockTest
    and both order-cache test setups. Enabling the same backend twice also
    repeats option lookups, a cache flush and the datastore assertion.

    Keep one enable before fixture construction and the existing cache-test
    state captures. Test bodies, backend scenarios and assertions remain
    unchanged.

    ---------

    Co-authored-by: Ján Mikláš <neosinner@gmail.com>

diff --git a/plugins/woocommerce/changelog/test-hpos-fixture-transaction-boundaries b/plugins/woocommerce/changelog/test-hpos-fixture-transaction-boundaries
new file mode 100644
index 00000000000..49e946797bc
--- /dev/null
+++ b/plugins/woocommerce/changelog/test-hpos-fixture-transaction-boundaries
@@ -0,0 +1,3 @@
+Significance: patch
+Type: dev
+Comment: Improve HPOS test fixture isolation and cleanup; no production change.
diff --git a/plugins/woocommerce/tests/legacy/framework/ddl-in-transaction-allowlist.php b/plugins/woocommerce/tests/legacy/framework/ddl-in-transaction-allowlist.php
index 31df10224dd..969926dc15b 100644
--- a/plugins/woocommerce/tests/legacy/framework/ddl-in-transaction-allowlist.php
+++ b/plugins/woocommerce/tests/legacy/framework/ddl-in-transaction-allowlist.php
@@ -16,13 +16,6 @@ return array(
 	// Creates the HPOS tables per test through setup_cot(). Move to wpSetUpBeforeClass() + setup_cot_tables(), as #68930 did.
 	'WC_Tests_API_Reports_Sales::test_get_sales_report_with_hpos_enabled_and_sync_off',

-	// Creates the HPOS tables in setUp() through setup_cot(). Move to wpSetUpBeforeClass() + setup_cot_tables(), as #68930 did.
-	'Automattic\WooCommerce\Tests\Internal\Admin\Orders\EditLockTest::*',
-	'Automattic\WooCommerce\Tests\Internal\Customers\SearchServiceTest::*',
-	'Automattic\WooCommerce\Tests\Internal\DataStores\Orders\LegacyDataCleanupTests::*',
-	'Automattic\WooCommerce\Tests\Internal\DataStores\Orders\OrdersTableDataStoreCacheCrossBleedTest::*',
-	'Automattic\WooCommerce\Tests\Internal\DataStores\Orders\OrdersTableDataStoreCachePrimingTest::*',
-
 	// setUp() recreates the HPOS tables whenever an earlier test dropped them, so which test trips depends on run order. Create them once before the class instead.
 	'Automattic\WooCommerce\Tests\Internal\DataStores\Orders\DataSynchronizerTests::*',

diff --git a/plugins/woocommerce/tests/php/src/Internal/Admin/Orders/EditLockTest.php b/plugins/woocommerce/tests/php/src/Internal/Admin/Orders/EditLockTest.php
index 0e414ef0ba1..9a695a7b390 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Admin/Orders/EditLockTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Admin/Orders/EditLockTest.php
@@ -12,6 +12,13 @@ use Automattic\WooCommerce\RestApi\UnitTests\HPOSToggleTrait;
 class EditLockTest extends \WC_Unit_Test_Case {
 	use HPOSToggleTrait;

+	/**
+	 * Ensure permanent HPOS tables exist before per-test transactions start.
+	 */
+	public static function wpSetUpBeforeClass(): void {
+		self::setup_cot_tables();
+	}
+
 	/**
 	 * @var EditLock
 	 */
@@ -46,7 +53,8 @@ class EditLockTest extends \WC_Unit_Test_Case {

 		add_filter( 'wc_allow_changing_orders_storage_while_sync_is_pending', '__return_true' );

-		$this->setup_cot();
+		remove_filter( 'query', array( $this, '_create_temporary_tables' ) );
+		remove_filter( 'query', array( $this, '_drop_temporary_tables' ) );
 		$this->toggle_cot_feature_and_usage( true );

 		$order = new \WC_Order();
diff --git a/plugins/woocommerce/tests/php/src/Internal/Customers/SearchServiceTest.php b/plugins/woocommerce/tests/php/src/Internal/Customers/SearchServiceTest.php
index bc6abbedf57..81e12d0465a 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Customers/SearchServiceTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Customers/SearchServiceTest.php
@@ -15,6 +15,13 @@ use Automattic\WooCommerce\Utilities\OrderUtil;
 class SearchServiceTest extends \WC_Unit_Test_Case {
 	use HPOSToggleTrait;

+	/**
+	 * Ensure permanent HPOS tables exist before per-test transactions start.
+	 */
+	public static function wpSetUpBeforeClass(): void {
+		self::setup_cot_tables();
+	}
+
 	/**
 	 * Service instance.
 	 *
@@ -38,7 +45,9 @@ class SearchServiceTest extends \WC_Unit_Test_Case {

 		$this->original_hpos_status = OrderUtil::custom_orders_table_usage_is_enabled();
 		if ( ! $this->original_hpos_status ) {
-			$this->setup_cot();
+			remove_filter( 'query', array( $this, '_create_temporary_tables' ) );
+			remove_filter( 'query', array( $this, '_drop_temporary_tables' ) );
+			$this->toggle_cot_feature_and_usage( true );
 		}
 	}

diff --git a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/LegacyDataCleanupTests.php b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/LegacyDataCleanupTests.php
index a2f0bb09a42..7a423c10bd5 100644
--- a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/LegacyDataCleanupTests.php
+++ b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/LegacyDataCleanupTests.php
@@ -14,6 +14,13 @@ use Automattic\WooCommerce\RestApi\UnitTests\HPOSToggleTrait;
 class LegacyDataCleanupTests extends \WC_Unit_Test_Case {
 	use HPOSToggleTrait;

+	/**
+	 * Ensure permanent HPOS tables exist before per-test transactions start.
+	 */
+	public static function wpSetUpBeforeClass(): void {
+		self::setup_cot_tables();
+	}
+
 	/**
 	 * @var LegacyDataCleanup
 	 */
@@ -26,7 +33,9 @@ class LegacyDataCleanupTests extends \WC_Unit_Test_Case {
 		parent::setUp();

 		add_filter( 'wc_allow_changing_orders_storage_while_sync_is_pending', '__return_true' );
-		$this->setup_cot();
+		remove_filter( 'query', array( $this, '_create_temporary_tables' ) );
+		remove_filter( 'query', array( $this, '_drop_temporary_tables' ) );
+		$this->toggle_cot_feature_and_usage( true );

 		$this->sut = wc_get_container()->get( LegacyDataCleanup::class );
 	}
@@ -35,9 +44,12 @@ class LegacyDataCleanupTests extends \WC_Unit_Test_Case {
 	 * Destroys system under test.
 	 */
 	public function tearDown(): void {
-		parent::tearDown();
-		$this->clean_up_cot_setup();
-		remove_all_filters( 'wc_allow_changing_orders_storage_while_sync_is_pending' );
+		try {
+			$this->clean_up_cot_setup();
+			remove_all_filters( 'wc_allow_changing_orders_storage_while_sync_is_pending' );
+		} finally {
+			parent::tearDown();
+		}
 	}

 	/**
diff --git a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreCacheCrossBleedTest.php b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreCacheCrossBleedTest.php
index 5b94151ea04..aebb6d05f34 100644
--- a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreCacheCrossBleedTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreCacheCrossBleedTest.php
@@ -17,6 +17,13 @@ use WC_Order;
 class OrdersTableDataStoreCacheCrossBleedTest extends \HposTestCase {
 	use HPOSToggleTrait;

+	/**
+	 * Ensure permanent HPOS tables exist before per-test transactions start.
+	 */
+	public static function wpSetUpBeforeClass(): void {
+		self::setup_cot_tables();
+	}
+
 	/**
 	 * The System Under Test.
 	 *
@@ -46,9 +53,10 @@ class OrdersTableDataStoreCacheCrossBleedTest extends \HposTestCase {

 		add_filter( 'wc_allow_changing_orders_storage_while_sync_is_pending', '__return_true' );

-		$this->setup_cot();
-		$this->cot_state = OrderUtil::custom_orders_table_usage_is_enabled();
+		remove_filter( 'query', array( $this, '_create_temporary_tables' ) );
+		remove_filter( 'query', array( $this, '_drop_temporary_tables' ) );
 		$this->toggle_cot_feature_and_usage( true );
+		$this->cot_state = OrderUtil::custom_orders_table_usage_is_enabled();
 		update_option( CustomOrdersTableController::HPOS_DATASTORE_CACHING_ENABLED_OPTION, 'yes' );

 		$container = wc_get_container();
diff --git a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreCachePrimingTest.php b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreCachePrimingTest.php
index 660502f2eed..4e1f38019a6 100644
--- a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreCachePrimingTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreCachePrimingTest.php
@@ -18,6 +18,13 @@ use WC_Tax;
 class OrdersTableDataStoreCachePrimingTest extends \HposTestCase {
 	use HPOSToggleTrait;

+	/**
+	 * Ensure permanent HPOS tables exist before per-test transactions start.
+	 */
+	public static function wpSetUpBeforeClass(): void {
+		self::setup_cot_tables();
+	}
+
 	/**
 	 * The System Under Test.
 	 *
@@ -40,9 +47,10 @@ class OrdersTableDataStoreCachePrimingTest extends \HposTestCase {

 		add_filter( 'wc_allow_changing_orders_storage_while_sync_is_pending', '__return_true' );

-		$this->setup_cot();
-		$this->cot_state = OrderUtil::custom_orders_table_usage_is_enabled();
+		remove_filter( 'query', array( $this, '_create_temporary_tables' ) );
+		remove_filter( 'query', array( $this, '_drop_temporary_tables' ) );
 		$this->toggle_cot_feature_and_usage( true );
+		$this->cot_state = OrderUtil::custom_orders_table_usage_is_enabled();

 		$container = wc_get_container();
 		$container->reset_all_resolved();