fix(2meet-data-optimizer): upgrade existing flat tables from WP-CLI or WP-Cron only
- a changed group definition no longer runs dbDelta on an existing table inside a web request (seconds to minutes on a large table, and every concurrent request tried it): the group is recorded in tmdo_schema_deferred and tmdo_ensure_group_indexes is scheduled, whose request upgrades it - meanwhile the group stays native: Hook Bus field lookups return no field and the router treats it as drifting; afterwards a drift fix (tmdo_drift_resync) rebuilds the writes that skipped the flat table - new tables are still created at once; aeav_only upgrades at once (the flat table is the only copy); doctor lists deferred groups - Verify: SchemaUpgradeDeferralTest, Hook Bus and router tests, integration 582, unit 701, phpcs, stan; dev36 live cycle in the 2.3 acceptance - PR: PR-107
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* An existing flat table whose definition changed is upgraded from WP-CLI /
|
||||
* WP-Cron only (2.3 PR-107); web requests record the group as deferred.
|
||||
*/
|
||||
class SchemaUpgradeDeferralTest extends TestCase {
|
||||
|
||||
private const TABLE = 'wp_itest_wpdo_user_sd_core';
|
||||
|
||||
public static function setUpBeforeClass(): void {
|
||||
$base = WPDO_PLUGIN_DIR;
|
||||
foreach ( array(
|
||||
'includes/adapters/interface-entity-adapter.php',
|
||||
'includes/engine/class-tmdo-type-caster.php',
|
||||
'includes/engine/class-tmdo-schema-manager.php',
|
||||
'includes/engine/class-tmdo-entity-registry.php',
|
||||
'includes/engine/class-tmdo-mode-manager.php',
|
||||
'includes/adapters/class-tmdo-adapter-user.php',
|
||||
) as $file ) {
|
||||
require_once $base . $file;
|
||||
}
|
||||
WPDO_Installer::install_v2_tables();
|
||||
}
|
||||
|
||||
protected function setUp(): void {
|
||||
global $wpdb;
|
||||
$wpdb->query( 'DROP TABLE IF EXISTS `' . self::TABLE . '`' );
|
||||
$wpdb->query( 'CREATE TABLE `' . self::TABLE . '` ( id BIGINT NOT NULL AUTO_INCREMENT, user_id BIGINT NOT NULL, sd_a VARCHAR(255) DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_entity (user_id) ) ENGINE=InnoDB' );
|
||||
$wpdb->delete( $wpdb->prefix . 'wpdo_registry_meta', array( 'entity_type' => 'user', 'group_name' => 'sd_core' ) );
|
||||
$wpdb->insert( $wpdb->prefix . 'wpdo_registry_meta', array( 'entity_type' => 'user', 'group_name' => 'sd_core', 'schema_hash' => 'old', 'field_definitions' => '[]' ) );
|
||||
|
||||
$GLOBALS['_wp_options'] = array();
|
||||
$GLOBALS['_wp_scheduled_single'] = array();
|
||||
$GLOBALS['_wp_filter_callbacks']['tmdo_schema_ddl_allowed'] = array(); // A web request.
|
||||
$ref = new ReflectionProperty( WPDO_Schema_Manager::class, 'table_exists_cache' );
|
||||
$ref->setAccessible( true );
|
||||
$ref->setValue( null, array() );
|
||||
self::set_user_mode( 'dual_write' );
|
||||
|
||||
WPDO_Entity_Registry::init();
|
||||
WPDO_Entity_Registry::register_adapter( 'user', new WPDO_Adapter_User() );
|
||||
WPDO_Entity_Registry::register_group( 'user', 'sd_core', array( array( 'key' => 'sd_a', 'type' => 'text' ), array( 'key' => 'sd_b', 'type' => 'integer' ) ) );
|
||||
}
|
||||
|
||||
protected function tearDown(): void {
|
||||
global $wpdb;
|
||||
$wpdb->query( 'DROP TABLE IF EXISTS `' . self::TABLE . '`' );
|
||||
$wpdb->delete( $wpdb->prefix . 'wpdo_registry_meta', array( 'entity_type' => 'user', 'group_name' => 'sd_core' ) );
|
||||
WPDO_Entity_Registry::init();
|
||||
self::set_user_mode( null );
|
||||
unset( $GLOBALS['_wp_scheduled_single'] );
|
||||
}
|
||||
|
||||
private static function set_user_mode( ?string $mode ): void {
|
||||
$ref = new ReflectionProperty( WPDO_Mode_Manager::class, 'cache' );
|
||||
$ref->setAccessible( true );
|
||||
$ref->setValue( null, null === $mode ? null : array( 'post' => 'disabled', 'user' => $mode, 'term' => 'disabled', 'comment' => 'disabled' ) );
|
||||
}
|
||||
|
||||
private function upgrade(): bool {
|
||||
return TMDO_Schema_Manager::create_or_upgrade_table( 'user', 'sd_core', WPDO_Entity_Registry::get_group_fields( 'user', 'sd_core' ) );
|
||||
}
|
||||
|
||||
public function test_a_web_request_leaves_the_upgrade_to_wp_cron_and_the_group_native(): void {
|
||||
global $wpdb;
|
||||
|
||||
$this->assertFalse( $this->upgrade() );
|
||||
|
||||
$this->assertTrue( TMDO_Schema_Manager::is_deferred( 'user', 'sd_core' ) );
|
||||
$this->assertContains( TMDO_Schema_Manager::INDEXES_HOOK, $GLOBALS['_wp_scheduled_single'] );
|
||||
$this->assertSame( array( 'id', 'user_id', 'sd_a' ), $wpdb->get_col( 'SHOW COLUMNS FROM `' . self::TABLE . '`' ), 'no ALTER' );
|
||||
$this->assertSame( 'old', TMDO_Schema_Manager::get_stored_schema_hash( 'user', 'sd_core' ) );
|
||||
}
|
||||
|
||||
public function test_only_existing_tables_outside_aeav_only_and_outside_cli_or_cron_wait(): void {
|
||||
$this->assertTrue( TMDO_Schema_Manager::upgrade_waits( 'user', self::TABLE ) );
|
||||
$this->assertFalse( TMDO_Schema_Manager::upgrade_waits( 'user', 'wp_itest_wpdo_user_sd_missing' ), 'a new table is created at once' );
|
||||
|
||||
self::set_user_mode( 'aeav_only' );
|
||||
$this->assertFalse( TMDO_Schema_Manager::upgrade_waits( 'user', self::TABLE ), 'aeav_only: the flat table is the only copy' );
|
||||
|
||||
self::set_user_mode( 'dual_write' );
|
||||
add_filter( 'tmdo_schema_ddl_allowed', static fn() => true ); // WP-CLI / WP-Cron.
|
||||
$this->assertFalse( TMDO_Schema_Manager::upgrade_waits( 'user', self::TABLE ) );
|
||||
$GLOBALS['_wp_filter_callbacks']['tmdo_schema_ddl_allowed'] = array();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user