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();