hardening 2.2: 2meet-data-optimizer 1.2.0 (drift detection, scope, CLI and diagnostics) #6
@@ -296,6 +296,9 @@ class TMDO_Core {
|
|||||||
// v2.3.0 M6: daily health probe cron.
|
// v2.3.0 M6: daily health probe cron.
|
||||||
add_action( 'wpdo_daily_health_check', array( 'TMDO_Health_Cron', 'run' ) );
|
add_action( 'wpdo_daily_health_check', array( 'TMDO_Health_Cron', 'run' ) );
|
||||||
|
|
||||||
|
// 1.2.0: daily flat-vs-native drift sample (read by the post query router).
|
||||||
|
add_action( 'wpdo_daily_health_check', array( 'TMDO_Drift_Check', 'cron_tick' ) );
|
||||||
|
|
||||||
// v2.3.0 M6: daily snapshot prune cron (paired with health check).
|
// v2.3.0 M6: daily snapshot prune cron (paired with health check).
|
||||||
add_action( 'wpdo_snapshot_prune_daily', array( 'TMDO_Snapshot_Pruner', 'cron_run' ) );
|
add_action( 'wpdo_snapshot_prune_daily', array( 'TMDO_Snapshot_Pruner', 'cron_run' ) );
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ final class TMDO_Drift_Check {
|
|||||||
*/
|
*/
|
||||||
public const OPTION = 'wpdo_drift_status';
|
public const OPTION = 'wpdo_drift_status';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entities per group sampled by the daily check.
|
||||||
|
*/
|
||||||
|
public const CRON_SAMPLE = 500;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MySQL regex for a plain decimal number, used to skip rows that obviously match.
|
* MySQL regex for a plain decimal number, used to skip rows that obviously match.
|
||||||
* Exact matches compare BINARY: meta and flat tables may differ in collation,
|
* Exact matches compare BINARY: meta and flat tables may differ in collation,
|
||||||
@@ -97,6 +102,24 @@ final class TMDO_Drift_Check {
|
|||||||
return $report;
|
return $report;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Daily check (wpdo_daily_health_check): sample every entity type whose
|
||||||
|
* flat tables are written (mode dual_write or higher). The outcome replaces
|
||||||
|
* the recorded status, so a group found drifting leaves the router at once.
|
||||||
|
*/
|
||||||
|
public static function cron_tick(): void {
|
||||||
|
foreach ( TMDO_Entity_Registry::VALID_ENTITY_TYPES as $entity_type ) {
|
||||||
|
if ( ! TMDO_Mode_Manager::writes_to_flat( $entity_type ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
self::run( $entity_type, '', self::CRON_SAMPLE );
|
||||||
|
} catch ( InvalidArgumentException $e ) {
|
||||||
|
continue; // No adapter for this entity type on this site.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rebuild drifted flat rows from native meta, then check again.
|
* Rebuild drifted flat rows from native meta, then check again.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -181,6 +181,45 @@ class DriftCheckTest extends TestCase {
|
|||||||
$this->assertFalse( TMDO_Cache_Orchestrator::get_row( 'user', 2, 'dc_grp' ) );
|
$this->assertFalse( TMDO_Cache_Orchestrator::get_row( 'user', 2, 'dc_grp' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── cron_tick() (2.2 PR-073) ────────────────────────────────────────────
|
||||||
|
|
||||||
|
private static function set_modes( ?array $modes ): void {
|
||||||
|
$cache = ( new ReflectionClass( WPDO_Mode_Manager::class ) )->getProperty( 'cache' );
|
||||||
|
$cache->setAccessible( true );
|
||||||
|
$cache->setValue( null, $modes );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_the_daily_tick_samples_entities_that_write_to_flat(): void {
|
||||||
|
self::set_modes( array( 'post' => 'disabled', 'user' => 'dual_write', 'term' => 'disabled', 'comment' => 'disabled' ) );
|
||||||
|
try {
|
||||||
|
TMDO_Drift_Check::cron_tick();
|
||||||
|
} finally {
|
||||||
|
self::set_modes( null );
|
||||||
|
}
|
||||||
|
|
||||||
|
$status = get_option( TMDO_Drift_Check::OPTION );
|
||||||
|
$this->assertSame( TMDO_Drift_Check::CRON_SAMPLE, $status['user']['dc_grp']['sample'] );
|
||||||
|
$this->assertSame( 2, $status['user']['dc_grp']['diff'], 'the sample covers all 7 fixture users' );
|
||||||
|
$this->assertArrayNotHasKey( 'post', $status );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_the_daily_tick_skips_entities_that_do_not_write_to_flat(): void {
|
||||||
|
self::set_modes( array( 'post' => 'disabled', 'user' => 'disabled', 'term' => 'disabled', 'comment' => 'disabled' ) );
|
||||||
|
try {
|
||||||
|
TMDO_Drift_Check::cron_tick();
|
||||||
|
} finally {
|
||||||
|
self::set_modes( null );
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertFalse( get_option( TMDO_Drift_Check::OPTION ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_the_daily_tick_runs_on_the_daily_health_check_hook(): void {
|
||||||
|
$source = (string) file_get_contents( WPDO_PLUGIN_DIR . 'includes/class-tmdo-core.php' );
|
||||||
|
|
||||||
|
$this->assertStringContainsString( "add_action( 'wpdo_daily_health_check', array( 'TMDO_Drift_Check', 'cron_tick' ) );", $source );
|
||||||
|
}
|
||||||
|
|
||||||
public function test_rejects_an_unknown_group(): void {
|
public function test_rejects_an_unknown_group(): void {
|
||||||
$this->expectException( InvalidArgumentException::class );
|
$this->expectException( InvalidArgumentException::class );
|
||||||
TMDO_Drift_Check::run( 'user', 'no_such_group' );
|
TMDO_Drift_Check::run( 'user', 'no_such_group' );
|
||||||
|
|||||||
Reference in New Issue
Block a user