edf9e6bc93
- A group's last drift record outlived its registration (wc_product and user hot on dev36, any add-on deactivated): doctor counted it and could warn forever with a --fix hint that cannot reach it. Only records of backfillable groups are read; the router and clean_since already go by the registry. - Verify: DoctorTest (RED before); dev36 doctor user 9 → 8 groups - PR: PR-089a
139 lines
4.6 KiB
PHP
139 lines
4.6 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
/**
|
|
* `wp tmdo doctor` false alarms (2.2 PR-076).
|
|
*
|
|
* The user flat tables were a hard-coded list including wpdo_user_sso, a group
|
|
* never registered: doctor reported it MISSING and failed on every site. The
|
|
* tables now come from the registry; doctor also reports Promotion Guard
|
|
* violations and the recorded drift status.
|
|
*/
|
|
class DoctorTest extends TestCase {
|
|
|
|
private const HAVE = 'wp_itest_wpdo_user_dt_have';
|
|
private const CORE = array( 'wp_itest_wpdo_migration_status', 'wp_itest_wpdo_user_points_ledger' );
|
|
|
|
public static function setUpBeforeClass(): void {
|
|
foreach ( array(
|
|
'includes/adapters/interface-entity-adapter.php',
|
|
'includes/adapters/class-tmdo-adapter-user.php',
|
|
'includes/engine/class-tmdo-promotion-guard.php',
|
|
'cli/class-tmdo-cli.php',
|
|
) as $file ) {
|
|
require_once WPDO_PLUGIN_DIR . $file;
|
|
}
|
|
}
|
|
|
|
protected function setUp(): void {
|
|
global $wpdb;
|
|
self::drop();
|
|
foreach ( array_merge( array( self::HAVE ), self::CORE ) as $table ) {
|
|
$wpdb->query( "CREATE TABLE `{$table}` ( id BIGINT NOT NULL AUTO_INCREMENT, user_id BIGINT NOT NULL DEFAULT 0, PRIMARY KEY (id) ) ENGINE=InnoDB" );
|
|
}
|
|
|
|
$GLOBALS['_wp_options'] = array();
|
|
$GLOBALS['_wp_cli_output'] = array();
|
|
TMDO_Mode_Manager::reset_cache();
|
|
WPDO_Entity_Registry::init();
|
|
WPDO_Entity_Registry::register_adapter( 'user', new WPDO_Adapter_User() );
|
|
WPDO_Entity_Registry::register_group( 'user', 'dt_have', array( array( 'key' => 'dt_a', 'type' => 'text' ) ) );
|
|
WPDO_Schema_Manager::flush_table_exists_cache();
|
|
}
|
|
|
|
protected function tearDown(): void {
|
|
self::drop();
|
|
WPDO_Entity_Registry::init();
|
|
TMDO_Mode_Manager::reset_cache();
|
|
}
|
|
|
|
private static function drop(): void {
|
|
global $wpdb;
|
|
foreach ( array_merge( array( self::HAVE ), self::CORE ) as $table ) {
|
|
$wpdb->query( "DROP TABLE IF EXISTS `{$table}`" );
|
|
}
|
|
}
|
|
|
|
private function cli_output(): string {
|
|
return implode( "\n", $GLOBALS['_wp_cli_output'] ?? array() );
|
|
}
|
|
|
|
public function test_entity_tables_come_from_the_registry(): void {
|
|
$ok = TMDO_CLI::check_entity_tables();
|
|
|
|
$this->assertTrue( $ok, $this->cli_output() );
|
|
$this->assertStringContainsString( '[OK] ' . self::HAVE, $this->cli_output() );
|
|
$this->assertStringNotContainsString( 'wpdo_user_sso', $this->cli_output() );
|
|
}
|
|
|
|
public function test_a_registered_group_without_its_table_is_reported(): void {
|
|
WPDO_Entity_Registry::register_group( 'user', 'dt_missing', array( array( 'key' => 'dt_b', 'type' => 'text' ) ) );
|
|
|
|
$ok = TMDO_CLI::check_entity_tables();
|
|
|
|
$this->assertFalse( $ok );
|
|
$this->assertStringContainsString( '[MISSING] wp_itest_wpdo_user_dt_missing', $this->cli_output() );
|
|
}
|
|
|
|
public function test_reports_drifting_groups(): void {
|
|
$GLOBALS['_wp_options']['wpdo_bridge_modes'] = array( 'user' => 'dual_write' );
|
|
$GLOBALS['_wp_options'][ TMDO_Drift_Check::OPTION ] = array(
|
|
'user' => array(
|
|
'dt_have' => array(
|
|
'miss' => 1,
|
|
'diff' => 2,
|
|
'extra' => 0,
|
|
'sample' => 0,
|
|
'checked_at' => '2026-09-27 00:00:00',
|
|
),
|
|
),
|
|
);
|
|
TMDO_Mode_Manager::reset_cache();
|
|
|
|
TMDO_CLI::report_guard_and_drift();
|
|
|
|
$this->assertStringContainsString( 'dt_have miss=1 diff=2 extra=0', $this->cli_output() );
|
|
$this->assertStringContainsString( 'wp tmdo drift-check user --fix', $this->cli_output() );
|
|
}
|
|
|
|
public function test_ignores_the_record_of_a_group_no_longer_registered(): void {
|
|
$GLOBALS['_wp_options']['wpdo_bridge_modes'] = array( 'user' => 'dual_write' );
|
|
$GLOBALS['_wp_options'][ TMDO_Drift_Check::OPTION ] = array(
|
|
'user' => array(
|
|
'dt_have' => array(
|
|
'miss' => 0,
|
|
'diff' => 0,
|
|
'extra' => 0,
|
|
'sample' => 0,
|
|
'checked_at' => '2026-09-27 00:00:00',
|
|
),
|
|
'dt_gone' => array(
|
|
'miss' => 3,
|
|
'diff' => 0,
|
|
'extra' => 0,
|
|
'sample' => 0,
|
|
'checked_at' => '2026-09-20 00:00:00',
|
|
),
|
|
),
|
|
);
|
|
TMDO_Mode_Manager::reset_cache();
|
|
|
|
TMDO_CLI::report_guard_and_drift();
|
|
|
|
$this->assertStringContainsString( '[OK] user: 1 group(s) clean (oldest check 2026-09-27 00:00:00 UTC)', $this->cli_output() );
|
|
$this->assertStringNotContainsString( 'dt_gone', $this->cli_output() );
|
|
}
|
|
|
|
public function test_reports_an_entity_never_checked(): void {
|
|
$GLOBALS['_wp_options']['wpdo_bridge_modes'] = array( 'user' => 'dual_write' );
|
|
TMDO_Mode_Manager::reset_cache();
|
|
|
|
TMDO_CLI::report_guard_and_drift();
|
|
|
|
$this->assertStringContainsString( 'user: never checked', $this->cli_output() );
|
|
$this->assertStringContainsString( 'Promotion Guard: no violation', $this->cli_output() );
|
|
}
|
|
}
|