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
+476
View File
@@ -0,0 +1,476 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
/**
* Integration test: WPDO_Post_Stress_Tester (v2.9.4).
*
* Verifies the post-side stress tester contract:
* - create() bulk-inserts N posts with 19 wc_product meta keys
* - count_test_posts() returns the correct count
* - cleanup() removes ALL test posts + their postmeta + flat rows
* - test posts use post_title prefix WPDO_STRESS_TEST_ for identification
*
* Mirrors the user-side WPDO_User_Stress_Tester contract but with a much
* narrower API surface — full polling/cron/benchmark UI deferred (v2.9.4
* scope is bulk fixture generation for v2.9.5 cutover validation).
*/
class PostStressTesterTest extends TestCase {
private const POSTS = 'wp_itest_posts';
private const POSTMETA = 'wp_itest_postmeta';
public static function setUpBeforeClass(): void {
global $wpdb;
if ( ! class_exists( 'WPDO_Post_Stress_Tester' ) ) {
require_once WPDO_PLUGIN_DIR . 'includes/class-tmdo-post-stress-tester.php';
}
$wpdb->query( 'DROP TABLE IF EXISTS `' . self::POSTS . '`' );
$wpdb->query(
'CREATE TABLE `' . self::POSTS . '` (
ID bigint(20) unsigned NOT NULL AUTO_INCREMENT,
post_title text NOT NULL,
post_type varchar(20) NOT NULL DEFAULT \'post\',
post_status varchar(20) NOT NULL DEFAULT \'publish\',
post_date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
post_date_gmt datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
post_modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
post_modified_gmt datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
post_author bigint(20) unsigned NOT NULL DEFAULT 0,
post_content longtext NOT NULL,
post_excerpt text NOT NULL,
comment_status varchar(20) NOT NULL DEFAULT \'open\',
ping_status varchar(20) NOT NULL DEFAULT \'open\',
post_password varchar(255) NOT NULL DEFAULT \'\',
post_name varchar(200) NOT NULL DEFAULT \'\',
to_ping text NOT NULL,
pinged text NOT NULL,
post_content_filtered longtext NOT NULL,
post_parent bigint(20) unsigned NOT NULL DEFAULT 0,
guid varchar(255) NOT NULL DEFAULT \'\',
menu_order int(11) NOT NULL DEFAULT 0,
post_mime_type varchar(100) NOT NULL DEFAULT \'\',
comment_count bigint(20) NOT NULL DEFAULT 0,
PRIMARY KEY (ID),
KEY post_type (post_type),
KEY post_title (post_title(64))
) DEFAULT CHARACTER SET utf8mb4'
);
$wpdb->query( 'DROP TABLE IF EXISTS `' . self::POSTMETA . '`' );
$wpdb->query(
'CREATE TABLE `' . self::POSTMETA . '` (
meta_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
post_id bigint(20) unsigned NOT NULL DEFAULT 0,
meta_key varchar(255) DEFAULT NULL,
meta_value longtext,
PRIMARY KEY (meta_id),
KEY post_id (post_id),
KEY meta_key (meta_key(191))
) DEFAULT CHARACTER SET utf8mb4'
);
}
public static function tearDownAfterClass(): void {
global $wpdb;
$wpdb->query( 'DROP TABLE IF EXISTS `' . self::POSTS . '`' );
$wpdb->query( 'DROP TABLE IF EXISTS `' . self::POSTMETA . '`' );
}
protected function setUp(): void {
global $wpdb;
$wpdb->query( 'TRUNCATE TABLE `' . self::POSTS . '`' );
$wpdb->query( 'TRUNCATE TABLE `' . self::POSTMETA . '`' );
}
// ── create() ──────────────────────────────────────────────────────────────
public function test_create_inserts_requested_count_of_products(): void {
$result = WPDO_Post_Stress_Tester::create( 'product', 5 );
$this->assertSame( 5, $result['created'] );
global $wpdb;
$count = (int) $wpdb->get_var(
"SELECT COUNT(*) FROM `" . self::POSTS . "` WHERE post_type = 'product'"
);
$this->assertSame( 5, $count );
}
public function test_create_uses_stress_test_prefix_in_post_title(): void {
WPDO_Post_Stress_Tester::create( 'product', 3 );
global $wpdb;
$prefix_count = (int) $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(*) FROM `" . self::POSTS . "` WHERE post_title LIKE %s",
WPDO_Post_Stress_Tester::TEST_POST_PREFIX . '%'
)
);
$this->assertSame( 3, $prefix_count );
}
public function test_create_seeds_postmeta_for_each_post(): void {
WPDO_Post_Stress_Tester::create( 'product', 2 );
global $wpdb;
// Each test product should have at least the 5 critical wc_product keys.
$meta_count = (int) $wpdb->get_var(
"SELECT COUNT(*) FROM `" . self::POSTMETA . "`"
);
$this->assertGreaterThanOrEqual( 10, $meta_count, 'At least 5 keys × 2 posts = 10 rows.' );
// Verify _price was set on every test product.
$price_count = (int) $wpdb->get_var(
"SELECT COUNT(*) FROM `" . self::POSTMETA . "` WHERE meta_key = '_price'"
);
$this->assertSame( 2, $price_count );
}
public function test_create_supports_hp_listing_post_type(): void {
$result = WPDO_Post_Stress_Tester::create( 'hp_listing', 4 );
$this->assertSame( 4, $result['created'] );
global $wpdb;
$count = (int) $wpdb->get_var(
"SELECT COUNT(*) FROM `" . self::POSTS . "` WHERE post_type = 'hp_listing'"
);
$this->assertSame( 4, $count );
// hp_listing seeds hp_price, not _price.
$hp_price_count = (int) $wpdb->get_var(
"SELECT COUNT(*) FROM `" . self::POSTMETA . "` WHERE meta_key = 'hp_price'"
);
$this->assertSame( 4, $hp_price_count );
}
public function test_create_rejects_unsupported_post_type(): void {
$this->expectException( InvalidArgumentException::class );
WPDO_Post_Stress_Tester::create( 'bogus_type', 3 );
}
public function test_create_rejects_zero_count(): void {
$this->expectException( InvalidArgumentException::class );
WPDO_Post_Stress_Tester::create( 'product', 0 );
}
public function test_create_rejects_excessive_count(): void {
$this->expectException( InvalidArgumentException::class );
WPDO_Post_Stress_Tester::create( 'product', 100001 );
}
// ── count_test_posts() ────────────────────────────────────────────────────
public function test_count_test_posts_returns_zero_for_empty(): void {
$this->assertSame( 0, WPDO_Post_Stress_Tester::count_test_posts() );
}
public function test_count_test_posts_counts_only_stress_prefix(): void {
// Seed 2 stress posts + 1 real post.
WPDO_Post_Stress_Tester::create( 'product', 2 );
global $wpdb;
$wpdb->insert( self::POSTS, array(
'ID' => 9999,
'post_title' => 'Real product not from stress',
'post_type' => 'product',
'post_content' => '',
'post_excerpt' => '',
'post_content_filtered' => '',
'to_ping' => '',
'pinged' => '',
) );
$this->assertSame( 2, WPDO_Post_Stress_Tester::count_test_posts() );
}
// ── cleanup() ─────────────────────────────────────────────────────────────
public function test_cleanup_removes_all_stress_posts_and_their_meta(): void {
WPDO_Post_Stress_Tester::create( 'product', 5 );
// Verify pre-state.
$this->assertSame( 5, WPDO_Post_Stress_Tester::count_test_posts() );
$result = WPDO_Post_Stress_Tester::cleanup();
$this->assertSame( 5, $result['deleted_posts'] );
global $wpdb;
$post_count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `" . self::POSTS . "`" );
$meta_count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `" . self::POSTMETA . "`" );
$this->assertSame( 0, $post_count );
$this->assertSame( 0, $meta_count, 'cleanup() must cascade delete postmeta.' );
}
public function test_cleanup_preserves_non_stress_posts(): void {
// Real post with prefix-collision-immune title.
global $wpdb;
$wpdb->insert( self::POSTS, array(
'ID' => 9999,
'post_title' => 'Real product not from stress',
'post_type' => 'product',
'post_content' => '',
'post_excerpt' => '',
'post_content_filtered' => '',
'to_ping' => '',
'pinged' => '',
) );
$wpdb->insert( self::POSTMETA, array(
'post_id' => 9999,
'meta_key' => '_price',
'meta_value' => '50.00',
) );
WPDO_Post_Stress_Tester::create( 'product', 3 );
$result = WPDO_Post_Stress_Tester::cleanup();
$this->assertSame( 3, $result['deleted_posts'] );
// Real post + its meta survive.
$remaining_posts = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `" . self::POSTS . "`" );
$remaining_meta = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `" . self::POSTMETA . "`" );
$this->assertSame( 1, $remaining_posts );
$this->assertSame( 1, $remaining_meta );
}
public function test_cleanup_idempotent_on_empty_state(): void {
$result1 = WPDO_Post_Stress_Tester::cleanup();
$result2 = WPDO_Post_Stress_Tester::cleanup();
$this->assertSame( 0, $result1['deleted_posts'] );
$this->assertSame( 0, $result2['deleted_posts'] );
}
// ── v2.11.2: create_realistic() — uses wp_insert_post + update_post_meta ─
public function test_create_realistic_uses_wp_insert_post(): void {
$result = WPDO_Post_Stress_Tester::create_realistic( 'product', 3 );
$this->assertSame( 3, $result['created'] );
$this->assertSame( 'realistic', $result['mode'] ?? '' );
global $wpdb;
$count = (int) $wpdb->get_var(
"SELECT COUNT(*) FROM `" . self::POSTS . "` WHERE post_type = 'product'"
);
$this->assertSame( 3, $count );
}
public function test_create_realistic_writes_postmeta_via_update_post_meta(): void {
$result = WPDO_Post_Stress_Tester::create_realistic( 'product', 2 );
$this->assertSame( 2, $result['created'] );
global $wpdb;
$price_count = (int) $wpdb->get_var(
"SELECT COUNT(*) FROM `" . self::POSTMETA . "` WHERE meta_key = '_price'"
);
$this->assertSame( 2, $price_count, 'Each realistic product seeds _price.' );
}
public function test_create_realistic_uses_stress_test_prefix(): void {
WPDO_Post_Stress_Tester::create_realistic( 'product', 2 );
global $wpdb;
$prefixed = (int) $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(*) FROM `" . self::POSTS . "` WHERE post_title LIKE %s",
WPDO_Post_Stress_Tester::TEST_POST_PREFIX . '%'
)
);
$this->assertSame( 2, $prefixed );
}
public function test_create_realistic_supports_hp_listing(): void {
$result = WPDO_Post_Stress_Tester::create_realistic( 'hp_listing', 4 );
$this->assertSame( 4, $result['created'] );
global $wpdb;
$hp_price_count = (int) $wpdb->get_var(
"SELECT COUNT(*) FROM `" . self::POSTMETA . "` WHERE meta_key = 'hp_price'"
);
$this->assertSame( 4, $hp_price_count );
}
public function test_create_realistic_rejects_unsupported_post_type(): void {
$this->expectException( InvalidArgumentException::class );
WPDO_Post_Stress_Tester::create_realistic( 'bogus_type', 2 );
}
public function test_create_realistic_rejects_invalid_count(): void {
$this->expectException( InvalidArgumentException::class );
WPDO_Post_Stress_Tester::create_realistic( 'product', 0 );
}
public function test_cleanup_removes_realistic_created_posts(): void {
WPDO_Post_Stress_Tester::create_realistic( 'product', 3 );
$this->assertSame( 3, WPDO_Post_Stress_Tester::count_test_posts() );
$cleanup = WPDO_Post_Stress_Tester::cleanup();
$this->assertSame( 3, $cleanup['deleted_posts'] );
$this->assertSame( 0, WPDO_Post_Stress_Tester::count_test_posts() );
}
// ── v2.11.4: state machine (start / cancel / get_state / get_progress / run_batch) ─
protected function tearDown(): void {
// Reset persisted state between state-machine tests so each test starts idle.
unset( $GLOBALS['_wp_options'][ WPDO_Post_Stress_Tester::OPT_STATE ] );
unset( $GLOBALS['_wp_transients'][ WPDO_Post_Stress_Tester::CANCEL_FLAG ] );
unset( $GLOBALS['_wp_transients']['wpdo_post_stress_pump_lock'] );
}
public function test_get_state_returns_empty_when_idle(): void {
$this->assertSame( array(), WPDO_Post_Stress_Tester::get_state() );
}
public function test_get_progress_returns_idle_when_no_state(): void {
$progress = WPDO_Post_Stress_Tester::get_progress( false );
$this->assertSame( 'idle', $progress['status'] );
$this->assertSame( 0, $progress['processed'] );
}
public function test_start_persists_state_with_running_status(): void {
$result = WPDO_Post_Stress_Tester::start( 'product', 10, 'fast', 5 );
$this->assertTrue( $result['ok'] );
$state = $result['state'];
$this->assertSame( 'running', $state['status'] );
$this->assertSame( 'product', $state['post_type'] );
$this->assertSame( 'fast', $state['mode'] );
$this->assertSame( 10, $state['target'] );
$this->assertSame( 5, $state['batch_size'] );
$this->assertSame( 0, $state['processed'] );
}
public function test_start_rejects_unsupported_post_type(): void {
$result = WPDO_Post_Stress_Tester::start( 'bogus_type', 10 );
$this->assertFalse( $result['ok'] );
$this->assertSame( 'unsupported_post_type', $result['error'] );
}
public function test_start_rejects_zero_target(): void {
$result = WPDO_Post_Stress_Tester::start( 'product', 0 );
$this->assertFalse( $result['ok'] );
}
public function test_start_rejects_excessive_target(): void {
$result = WPDO_Post_Stress_Tester::start( 'product', 100001 );
$this->assertFalse( $result['ok'] );
}
public function test_start_rejects_invalid_mode(): void {
$result = WPDO_Post_Stress_Tester::start( 'product', 10, 'turbo' );
$this->assertFalse( $result['ok'] );
$this->assertSame( 'invalid mode', $result['error'] );
}
public function test_start_rejects_concurrent_run(): void {
WPDO_Post_Stress_Tester::start( 'product', 10 );
$result = WPDO_Post_Stress_Tester::start( 'product', 5 );
$this->assertFalse( $result['ok'] );
$this->assertSame( 'already_running', $result['error'] );
}
public function test_start_clamps_batch_size_above_max(): void {
$result = WPDO_Post_Stress_Tester::start( 'product', 10, 'fast', 5000 );
$this->assertTrue( $result['ok'] );
$this->assertSame( WPDO_Post_Stress_Tester::MAX_BATCH_SIZE, $result['state']['batch_size'] );
}
public function test_run_batch_advances_processed_count(): void {
WPDO_Post_Stress_Tester::start( 'product', 6, 'fast', 3 );
WPDO_Post_Stress_Tester::run_batch();
$progress = WPDO_Post_Stress_Tester::get_progress( false );
$this->assertSame( 3, $progress['processed'] );
$this->assertSame( 1, $progress['batches_done'] );
$this->assertSame( 'running', $progress['status'] );
WPDO_Post_Stress_Tester::run_batch();
$progress = WPDO_Post_Stress_Tester::get_progress( false );
$this->assertSame( 6, $progress['processed'] );
$this->assertSame( 'completed', $progress['status'] );
}
public function test_run_batch_creates_actual_posts(): void {
WPDO_Post_Stress_Tester::start( 'product', 4, 'fast', 4 );
WPDO_Post_Stress_Tester::run_batch();
$this->assertSame( 4, WPDO_Post_Stress_Tester::count_test_posts() );
}
public function test_run_batch_finalizes_with_benchmark(): void {
WPDO_Post_Stress_Tester::start( 'product', 2, 'fast', 2 );
WPDO_Post_Stress_Tester::run_batch();
$state = WPDO_Post_Stress_Tester::get_state();
$this->assertSame( 'completed', $state['status'] );
$this->assertIsArray( $state['benchmark'] );
$this->assertArrayHasKey( 'write', $state['benchmark'] );
$this->assertArrayHasKey( 'db_sizes', $state['benchmark'] );
$this->assertSame( 'product', $state['benchmark']['post_type'] );
}
public function test_cancel_marks_state_as_cancelled(): void {
WPDO_Post_Stress_Tester::start( 'product', 100, 'fast', 50 );
$result = WPDO_Post_Stress_Tester::cancel();
$this->assertTrue( $result['ok'] );
$this->assertSame( 'cancelled', $result['state']['status'] );
// In-flight batch run after cancel must NOT bump status back to running.
WPDO_Post_Stress_Tester::run_batch();
$state = WPDO_Post_Stress_Tester::get_state();
$this->assertSame( 'cancelled', $state['status'] );
}
public function test_cancel_returns_no_active_job_when_idle(): void {
$result = WPDO_Post_Stress_Tester::cancel();
$this->assertTrue( $result['ok'] );
$this->assertSame( 'no_active_job', $result['message'] ?? '' );
}
public function test_get_progress_includes_pct_and_eta(): void {
WPDO_Post_Stress_Tester::start( 'product', 10, 'fast', 5 );
WPDO_Post_Stress_Tester::run_batch();
$progress = WPDO_Post_Stress_Tester::get_progress( false );
$this->assertArrayHasKey( 'pct', $progress );
$this->assertArrayHasKey( 'rate_per_sec', $progress );
$this->assertArrayHasKey( 'elapsed_sec', $progress );
$this->assertArrayHasKey( 'eta_sec', $progress );
$this->assertArrayHasKey( 'test_post_count', $progress );
$this->assertSame( 50.0, $progress['pct'] ); // 5/10 = 50%
}
public function test_run_benchmark_returns_post_type_aware_query_probes(): void {
WPDO_Post_Stress_Tester::start( 'hp_listing', 4, 'fast', 4 );
WPDO_Post_Stress_Tester::run_batch();
$state = WPDO_Post_Stress_Tester::get_state();
$bench = $state['benchmark'];
$this->assertSame( 'hp_listing', $bench['post_type'] );
// query is post_type-aware; in production the flat table exists so this
// returns 3 probes (point/range/eav_baseline). In integration tests the
// flat table doesn't exist (different prefix), so we only verify the
// structure is present and post_type-aware.
$this->assertIsArray( $bench['query'] );
}
public function test_run_batch_realistic_uses_wp_insert_post(): void {
WPDO_Post_Stress_Tester::start( 'product', 3, 'realistic', 3 );
WPDO_Post_Stress_Tester::run_batch();
$state = WPDO_Post_Stress_Tester::get_state();
$this->assertSame( 'completed', $state['status'] );
$this->assertSame( 3, $state['processed'] );
$this->assertSame( 'realistic', $state['mode'] );
}
}