chore: initial snapshot of 2meet-data-optimizer v0.1.0

Baseline before backporting wp-data-optimizer v3.0.1-v3.4.6.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
This commit is contained in:
2026-07-31 05:06:36 +08:00
commit d36bb954d1
206 changed files with 66538 additions and 0 deletions
+140
View File
@@ -0,0 +1,140 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
if ( ! function_exists( '__' ) ) {
function __( string $text, string $domain = 'default' ): string {
return $text;
}
}
require_once dirname( __DIR__, 3 ) . '/includes/class-tmdo-logger.php';
require_once dirname( __DIR__, 3 ) . '/includes/class-tmdo-feature-flags.php';
require_once dirname( __DIR__, 3 ) . '/includes/advisor/class-tmdo-fsm-advisor.php';
/**
* Unit tests for WPDO_FSM_Advisor (v2.4.0 M12).
*
* Pure-logic tests — uses option-driven state injection (no real DB).
*/
class FSMAdvisorTest extends TestCase {
protected function setUp(): void {
$GLOBALS['_wp_options'] = array();
$this->setup_wpdb_mock();
}
private function setup_wpdb_mock(): void {
global $wpdb;
$wpdb = new class {
public string $prefix = 'wp_';
public string $postmeta = 'wp_postmeta';
public string $options = 'wp_options';
public function prepare( string $sql, ...$args ): string {
$i = 0;
return preg_replace_callback( '/%[sd]/', function() use ( &$i, $args ) {
return (string) ( $args[ $i++ ] ?? '?' );
}, $sql );
}
public function get_var( string $sql ) { return '0'; } // shadow_diffs table absent
public function get_results( string $sql, $output = ARRAY_A ): array { return array(); }
};
}
private function set_module_state( string $module, string $state, ?int $days_ago = null ): void {
// Set FSM state.
$flags = (array) get_option( 'wpdo_features', array() );
$flags[ $module ] = $state;
update_option( 'wpdo_features', $flags, false );
// Reset Feature_Flags request cache via reflection.
$ref = new ReflectionClass( WPDO_Feature_Flags::class );
$prop = $ref->getProperty( 'cache' );
$prop->setAccessible( true );
$prop->setValue( null, null );
if ( null !== $days_ago ) {
$entered = (array) get_option( 'wpdo_fsm_state_entered', array() );
$entered[ $module ] = array(
'state' => $state,
'entered_at' => gmdate( 'Y-m-d H:i:s', time() - $days_ago * 86400 ),
);
update_option( 'wpdo_fsm_state_entered', $entered, false );
}
}
public function test_idle_state_returns_HOLD(): void {
$this->set_module_state( 'reviews', 'idle' );
$advice = WPDO_FSM_Advisor::advise( 'reviews' );
$this->assertSame( 'HOLD', $advice['action'] );
$this->assertSame( 'info', $advice['level'] );
}
public function test_complete_state_returns_HOLD(): void {
$this->set_module_state( 'reviews', 'complete' );
$advice = WPDO_FSM_Advisor::advise( 'reviews' );
$this->assertSame( 'HOLD', $advice['action'] );
}
public function test_dual_write_with_short_soak_returns_WAIT(): void {
// In dual_write 0 days < 1 day min soak.
$this->set_module_state( 'reviews', 'dual_write', 0 );
$advice = WPDO_FSM_Advisor::advise( 'reviews' );
$this->assertSame( 'WAIT', $advice['action'] );
$this->assertGreaterThanOrEqual( 1, $advice['days_remaining'] );
}
public function test_dual_write_after_min_soak_returns_PROMOTE(): void {
$this->set_module_state( 'reviews', 'dual_write', 2 );
$advice = WPDO_FSM_Advisor::advise( 'reviews' );
$this->assertSame( 'PROMOTE', $advice['action'] );
$this->assertSame( 'backfill', $advice['next_state'] );
}
public function test_verify_with_long_soak_returns_PROMOTE(): void {
// verify needs 7 days; 10 days = should promote.
$this->set_module_state( 'reviews', 'verify', 10 );
$advice = WPDO_FSM_Advisor::advise( 'reviews' );
$this->assertSame( 'PROMOTE', $advice['action'] );
$this->assertSame( 'cutover', $advice['next_state'] );
}
public function test_verify_with_short_soak_returns_WAIT(): void {
$this->set_module_state( 'reviews', 'verify', 3 );
$advice = WPDO_FSM_Advisor::advise( 'reviews' );
$this->assertSame( 'WAIT', $advice['action'] );
$this->assertSame( 4, $advice['days_remaining'] );
}
public function test_cleanup_with_short_wash_returns_WAIT(): void {
$this->set_module_state( 'reviews', 'cleanup', 1 );
$advice = WPDO_FSM_Advisor::advise( 'reviews' );
$this->assertSame( 'WAIT', $advice['action'] );
$this->assertSame( 2, $advice['days_remaining'] );
}
public function test_cleanup_after_wash_returns_PROMOTE(): void {
$this->set_module_state( 'reviews', 'cleanup', 5 );
$advice = WPDO_FSM_Advisor::advise( 'reviews' );
$this->assertSame( 'PROMOTE', $advice['action'] );
$this->assertSame( 'complete', $advice['next_state'] );
}
public function test_advice_metrics_include_state_and_soak(): void {
$this->set_module_state( 'reviews', 'dual_write', 5 );
$advice = WPDO_FSM_Advisor::advise( 'reviews' );
$this->assertSame( 'dual_write', $advice['metrics']['state'] );
$this->assertSame( 5, $advice['metrics']['days_in_state'] );
$this->assertSame( 1, $advice['metrics']['min_soak_days'] );
}
public function test_advise_all_returns_map_for_all_modules(): void {
$advice = WPDO_FSM_Advisor::advise_all();
$this->assertNotEmpty( $advice );
// All known HPCT + zone modules should be present (default idle).
foreach ( WPDO_Feature_Flags::HPCT_MODULES as $m ) {
$this->assertArrayHasKey( $m, $advice );
}
}
}
+119
View File
@@ -0,0 +1,119 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
if ( ! function_exists( '__' ) ) {
function __( string $text, string $domain = 'default' ): string { return $text; }
}
require_once dirname( __DIR__, 3 ) . '/includes/class-tmdo-logger.php';
require_once dirname( __DIR__, 3 ) . '/includes/class-tmdo-feature-flags.php';
require_once dirname( __DIR__, 3 ) . '/includes/advisor/class-tmdo-fsm-advisor.php';
require_once dirname( __DIR__, 3 ) . '/includes/diagnostic/class-tmdo-health-cron.php';
require_once dirname( __DIR__, 3 ) . '/includes/advisor/class-tmdo-fsm-automator.php';
/**
* Unit tests for WPDO_FSM_Automator (v2.5.0 M13).
*/
class FSMAutomatorTest extends TestCase {
protected function setUp(): void {
$GLOBALS['_wp_options'] = array();
// Reset Feature_Flags cache.
$ref = new ReflectionClass( WPDO_Feature_Flags::class );
$prop = $ref->getProperty( 'cache' );
$prop->setAccessible( true );
$prop->setValue( null, null );
$this->setup_wpdb_mock();
}
private function setup_wpdb_mock(): void {
global $wpdb;
$wpdb = new class {
public string $prefix = 'wp_';
public string $postmeta = 'wp_postmeta';
public string $options = 'wp_options';
public function prepare( string $sql, ...$args ): string { return $sql; }
public function get_var( string $sql ) { return '0'; }
public function get_results( string $sql, $output = ARRAY_A ): array { return array(); }
};
}
public function test_default_disabled(): void {
$this->assertFalse( WPDO_FSM_Automator::is_enabled() );
}
public function test_run_returns_disabled_when_off(): void {
$result = WPDO_FSM_Automator::run();
$this->assertFalse( $result['ok'] );
$this->assertContains( 'automator disabled', $result['errors'] );
}
public function test_run_blocked_by_critical_cool_off(): void {
// Enable + simulate critical alert in last run.
update_option( 'wpdo_automator_enabled', '1', false );
update_option( WPDO_Health_Cron::OPTION_LAST_RUN, array(
'critical_count' => 2,
'ran_at' => gmdate( 'Y-m-d H:i:s' ),
), false );
$result = WPDO_FSM_Automator::run();
$this->assertFalse( $result['ok'] );
$this->assertStringContainsString( 'cool-off', $result['errors'][0] );
}
public function test_run_proceeds_when_no_critical(): void {
update_option( 'wpdo_automator_enabled', '1', false );
update_option( WPDO_Health_Cron::OPTION_LAST_RUN, array(
'critical_count' => 0,
'ran_at' => gmdate( 'Y-m-d H:i:s' ),
), false );
$result = WPDO_FSM_Automator::run();
$this->assertTrue( $result['ok'] );
// Most modules will be in idle and Advisor recommends WAIT (soak time);
// expected that 0 actions are executed in baseline test.
$this->assertGreaterThanOrEqual( 0, $result['executed'] );
}
public function test_blacklist_skips_module(): void {
update_option( 'wpdo_automator_enabled', '1', false );
update_option( 'wpdo_automator_blacklist', array( 'reviews', 'wc_orders' ), false );
update_option( WPDO_Health_Cron::OPTION_LAST_RUN, array(
'critical_count' => 0,
'ran_at' => gmdate( 'Y-m-d H:i:s' ),
), false );
$blacklist = WPDO_FSM_Automator::blacklist();
$this->assertContains( 'reviews', $blacklist );
$this->assertContains( 'wc_orders', $blacklist );
$result = WPDO_FSM_Automator::run();
$this->assertTrue( $result['ok'] );
// Skipped at least the 2 blacklisted ones.
$this->assertGreaterThanOrEqual( 2, $result['skipped'] );
}
public function test_forbidden_transitions_constant(): void {
$ref = new ReflectionClass( WPDO_FSM_Automator::class );
$constant = $ref->getReflectionConstant( 'FORBIDDEN_TRANSITIONS' );
$this->assertNotNull( $constant );
$value = $constant->getValue();
$this->assertContains( array( 'verify', 'cutover' ), $value );
$this->assertContains( array( 'cutover', 'cleanup' ), $value );
$this->assertContains( array( 'cleanup', 'complete' ), $value );
}
public function test_options_keys_match_admin_form(): void {
$this->assertSame( 'wpdo_automator_enabled', WPDO_FSM_Automator::OPT_ENABLED );
$this->assertSame( 'wpdo_automator_blacklist', WPDO_FSM_Automator::OPT_BLACKLIST );
$this->assertSame( 'wpdo_automator_last_action', WPDO_FSM_Automator::OPT_LAST_ACTION );
}
public function test_last_actions_returns_array(): void {
$this->assertSame( array(), WPDO_FSM_Automator::last_actions() );
update_option( 'wpdo_automator_last_action', array( 'reviews' => '2026-04-28 04:30:00' ), false );
$last = WPDO_FSM_Automator::last_actions();
$this->assertSame( '2026-04-28 04:30:00', $last['reviews'] );
}
}
+160
View File
@@ -0,0 +1,160 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
if ( ! function_exists( '__' ) ) {
function __( string $text, string $domain = 'default' ): string { return $text; }
}
if ( ! function_exists( 'number_format_i18n' ) ) {
function number_format_i18n( $n, int $decimals = 0 ): string {
return number_format( (float) $n, $decimals );
}
}
require_once dirname( __DIR__, 3 ) . '/includes/class-tmdo-logger.php';
require_once dirname( __DIR__, 3 ) . '/includes/class-tmdo-feature-flags.php';
require_once dirname( __DIR__, 3 ) . '/includes/advisor/class-tmdo-module-rules.php';
require_once dirname( __DIR__, 3 ) . '/includes/advisor/class-tmdo-module-detector.php';
/**
* Unit tests for WPDO_Module_Rules + WPDO_Module_Detector (v2.5.0 M16).
*
* Pure-logic tests using mocked WPDO_Compatibility (via dynamic class
* substitution where needed) and option-driven post counts.
*/
class ModuleDetectorTest extends TestCase {
protected function setUp(): void {
$GLOBALS['_wp_options'] = array();
// Reset Feature_Flags cache.
$ref = new ReflectionClass( WPDO_Feature_Flags::class );
$prop = $ref->getProperty( 'cache' );
$prop->setAccessible( true );
$prop->setValue( null, null );
$this->setup_wpdb_mock();
}
private function setup_wpdb_mock(): void {
global $wpdb;
$wpdb = new class {
public string $prefix = 'wp_';
public string $posts = 'wp_posts';
public string $postmeta = 'wp_postmeta';
public string $options = 'wp_options';
public array $count_overrides = array();
public function prepare( string $sql, ...$args ): string {
$i = 0;
return preg_replace_callback( '/%[sd]/', function() use ( &$i, $args ) {
return is_string( $args[ $i ] ?? null ) ? "'" . $args[ $i++ ] . "'" : (string) ( $args[ $i++ ] ?? '?' );
}, $sql );
}
public function get_var( string $sql ) {
// Mock by inspecting SQL pattern.
if ( str_contains( $sql, "post_type =" ) ) {
if ( preg_match( "/post_type = '([^']+)'/", $sql, $m ) ) {
return (string) ( $this->count_overrides[ $m[1] ] ?? 0 );
}
}
if ( str_contains( $sql, "post_status = 'trash'" ) ) {
return (string) ( $this->count_overrides['__trash__'] ?? 0 );
}
return '0';
}
public function get_results( string $sql, $output = ARRAY_A ): array { return array(); }
};
}
public function test_module_rules_known_modules_count(): void {
$modules = WPDO_Module_Rules::known_modules();
$this->assertGreaterThanOrEqual( 14, count( $modules ), '預期 ≥ 14 個 module9 HPCT + 6 zone - 1 dup' );
$this->assertContains( 'reviews', $modules );
$this->assertContains( 'warm', $modules );
$this->assertContains( 'archive', $modules );
$this->assertContains( 'hot_hp_listing', $modules );
}
public function test_module_rule_for_module_returns_array(): void {
$rule = WPDO_Module_Rules::for_module( 'reviews' );
$this->assertIsArray( $rule );
$this->assertArrayHasKey( 'compat_required', $rule );
$this->assertArrayHasKey( 'description', $rule );
}
public function test_module_rule_unknown_module_returns_null(): void {
$this->assertNull( WPDO_Module_Rules::for_module( 'totally_fake_module_xyz' ) );
}
public function test_detector_skip_when_module_not_idle(): void {
// Set reviews to dual_write.
WPDO_Feature_Flags::set( 'reviews', 'dual_write' );
$r = WPDO_Module_Detector::detect_one( 'reviews' );
$this->assertSame( 'skip', $r['recommendation'] );
$this->assertFalse( $r['available'] );
$this->assertNotEmpty( $r['blockers'] );
$this->assertSame( 'dual_write', $r['current_state'] );
}
public function test_detector_warm_module_recommends_for_any_site(): void {
// warm module's compat_required is empty + no post_type.
$r = WPDO_Module_Detector::detect_one( 'warm' );
$this->assertTrue( $r['available'] );
$this->assertSame( 'enable', $r['recommendation'] );
$this->assertGreaterThan( 0, $r['confidence'] );
$this->assertNotEmpty( $r['suggested_action'] );
$this->assertSame( 'dual_write', $r['suggested_action']['to_state'] );
}
public function test_detector_archive_blocked_when_no_trashed_posts(): void {
// trashed = 0, threshold = 50.
global $wpdb;
$wpdb->count_overrides['__trash__'] = 0;
$r = WPDO_Module_Detector::detect_one( 'archive' );
$this->assertSame( 'wait', $r['recommendation'] );
$this->assertFalse( $r['available'] );
}
public function test_detector_archive_passes_when_enough_trashed(): void {
global $wpdb;
$wpdb->count_overrides['__trash__'] = 100;
$r = WPDO_Module_Detector::detect_one( 'archive' );
$this->assertSame( 'enable', $r['recommendation'] );
$this->assertTrue( $r['available'] );
}
public function test_detector_hivepress_required_blocks_when_inactive(): void {
// reviews requires hivepress; Compatibility class isn't loaded in this test.
// Without Compatibility class, the helper returns the full required list as missing.
$r = WPDO_Module_Detector::detect_one( 'reviews' );
$this->assertSame( 'skip', $r['recommendation'] );
$this->assertNotEmpty( $r['blockers'] );
}
public function test_get_actionable_filters_by_confidence(): void {
$actionable = WPDO_Module_Detector::get_actionable( 0.5 );
$this->assertIsArray( $actionable );
// Each result should have available=true and recommendation=enable.
foreach ( $actionable as $module => $r ) {
$this->assertTrue( $r['available'], "$module should be available" );
$this->assertSame( 'enable', $r['recommendation'] );
$this->assertGreaterThanOrEqual( 0.5, $r['confidence'] );
}
}
public function test_get_actionable_sorts_by_confidence_desc(): void {
$actionable = WPDO_Module_Detector::get_actionable( 0.0 );
$last_confidence = 1.0;
foreach ( $actionable as $r ) {
$this->assertLessThanOrEqual( $last_confidence, (float) $r['confidence'] );
$last_confidence = (float) $r['confidence'];
}
}
public function test_detect_all_returns_entry_for_each_known_module(): void {
$all = WPDO_Module_Detector::detect_all( true );
$known = WPDO_Module_Rules::known_modules();
foreach ( $known as $m ) {
$this->assertArrayHasKey( $m, $all, "Detector should return entry for $m" );
}
}
}