posts = self::POSTS; $wpdb->comments = self::COMMENTS; $wpdb->commentmeta = self::COMMENTMETA; $wpdb->query( 'CREATE TABLE IF NOT EXISTS `' . self::POSTS . '` ( ID bigint(20) unsigned NOT NULL AUTO_INCREMENT, post_title text NOT NULL DEFAULT "", post_status varchar(20) NOT NULL DEFAULT "publish", post_type varchar(20) NOT NULL DEFAULT "post", comment_count bigint(20) NOT NULL DEFAULT 0, PRIMARY KEY (ID) ) DEFAULT CHARACTER SET utf8mb4' ); $wpdb->query( 'DROP TABLE IF EXISTS `' . self::COMMENTS . '`' ); $wpdb->query( 'CREATE TABLE `' . self::COMMENTS . '` ( comment_ID bigint(20) unsigned NOT NULL AUTO_INCREMENT, comment_post_ID bigint(20) unsigned NOT NULL DEFAULT 0, comment_author tinytext NOT NULL, comment_author_email varchar(100) NOT NULL DEFAULT "", comment_author_url varchar(200) NOT NULL DEFAULT "", comment_author_IP varchar(100) NOT NULL DEFAULT "", comment_date datetime NOT NULL DEFAULT "1970-01-01 00:00:00", comment_date_gmt datetime NOT NULL DEFAULT "1970-01-01 00:00:00", comment_content text NOT NULL, comment_karma int(11) NOT NULL DEFAULT 0, comment_approved varchar(20) NOT NULL DEFAULT "1", comment_agent varchar(255) NOT NULL DEFAULT "", comment_type varchar(20) NOT NULL DEFAULT "comment", comment_parent bigint(20) unsigned NOT NULL DEFAULT 0, user_id bigint(20) unsigned NOT NULL DEFAULT 0, PRIMARY KEY (comment_ID), KEY comment_author_email (comment_author_email(10)), KEY comment_post_ID (comment_post_ID) ) DEFAULT CHARACTER SET utf8mb4' ); $wpdb->query( 'CREATE TABLE IF NOT EXISTS `' . self::COMMENTMETA . '` ( meta_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, comment_id bigint(20) unsigned NOT NULL DEFAULT 0, meta_key varchar(255) DEFAULT NULL, meta_value longtext, PRIMARY KEY (meta_id), KEY comment_id (comment_id), KEY meta_key (meta_key(191)) ) DEFAULT CHARACTER SET utf8mb4' ); // Seed a single fixture post to satisfy post_exists() checks. $wpdb->query( 'TRUNCATE TABLE `' . self::POSTS . '`' ); $wpdb->insert( self::POSTS, array( 'post_title' => 'WPDO Comment Stress Fixture Post', 'post_status' => 'publish', 'post_type' => 'post', ) ); self::$test_post_id = (int) $wpdb->insert_id; } public static function tearDownAfterClass(): void { global $wpdb; foreach ( array( self::COMMENTS, self::COMMENTMETA ) as $tbl ) { $wpdb->query( 'DROP TABLE IF EXISTS `' . $tbl . '`' ); } // Don't drop wp_itest_posts — shared fixture across test classes. } protected function setUp(): void { global $wpdb; $wpdb->query( 'TRUNCATE TABLE `' . self::COMMENTS . '`' ); $wpdb->query( 'TRUNCATE TABLE `' . self::COMMENTMETA . '`' ); // Reset state per test so each starts idle. unset( $GLOBALS['_wp_options'][ WPDO_Comment_Stress_Tester::OPT_STATE ] ); unset( $GLOBALS['_wp_transients'][ WPDO_Comment_Stress_Tester::CANCEL_FLAG ] ); unset( $GLOBALS['_wp_transients']['wpdo_comment_stress_pump_lock'] ); } // ── create() (fast-path direct SQL) ────────────────────────────────────── public function test_create_inserts_comments_for_post(): void { $result = WPDO_Comment_Stress_Tester::create( self::$test_post_id, 5 ); $this->assertSame( 5, $result['created'] ); $this->assertSame( self::$test_post_id, $result['post_id'] ); $this->assertNotNull( $result['first_id'] ); $this->assertNotNull( $result['last_id'] ); global $wpdb; $count = (int) $wpdb->get_var( 'SELECT COUNT(*) FROM `' . self::COMMENTS . '`' ); $this->assertSame( 5, $count ); } public function test_create_uses_stress_email_domain(): void { WPDO_Comment_Stress_Tester::create( self::$test_post_id, 3 ); global $wpdb; $prefix_count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM `" . self::COMMENTS . "` WHERE comment_author_email LIKE %s", '%@' . WPDO_Comment_Stress_Tester::TEST_EMAIL_DOMAIN ) ); $this->assertSame( 3, $prefix_count ); } public function test_create_seeds_commentmeta_keys(): void { WPDO_Comment_Stress_Tester::create( self::$test_post_id, 3 ); global $wpdb; $total_meta = (int) $wpdb->get_var( 'SELECT COUNT(*) FROM `' . self::COMMENTMETA . '`' ); // 3 comments × 1 key (hp_rating) = 3. $this->assertSame( 3, $total_meta ); } public function test_create_rejects_bad_post_id(): void { $this->expectException( InvalidArgumentException::class ); WPDO_Comment_Stress_Tester::create( 0, 3 ); } public function test_create_rejects_zero_count(): void { $this->expectException( InvalidArgumentException::class ); WPDO_Comment_Stress_Tester::create( self::$test_post_id, 0 ); } public function test_create_rejects_excessive_count(): void { $this->expectException( InvalidArgumentException::class ); WPDO_Comment_Stress_Tester::create( self::$test_post_id, 100001 ); } // ── count_test_comments() ──────────────────────────────────────────────── public function test_count_test_comments_returns_zero_for_empty(): void { $this->assertSame( 0, WPDO_Comment_Stress_Tester::count_test_comments() ); } public function test_count_test_comments_counts_only_stress_emails(): void { WPDO_Comment_Stress_Tester::create( self::$test_post_id, 4 ); global $wpdb; $wpdb->insert( self::COMMENTS, array( 'comment_post_ID' => self::$test_post_id, 'comment_author' => 'Real', 'comment_author_email' => 'real@example.com', 'comment_content' => 'Real comment', 'comment_approved' => '1', ) ); $this->assertSame( 4, WPDO_Comment_Stress_Tester::count_test_comments() ); } // ── cleanup() ───────────────────────────────────────────────────────────── public function test_cleanup_removes_test_comments_and_cascade(): void { WPDO_Comment_Stress_Tester::create( self::$test_post_id, 5 ); $this->assertSame( 5, WPDO_Comment_Stress_Tester::count_test_comments() ); $result = WPDO_Comment_Stress_Tester::cleanup(); $this->assertSame( 5, $result['deleted_comments'] ); global $wpdb; $this->assertSame( 0, (int) $wpdb->get_var( 'SELECT COUNT(*) FROM `' . self::COMMENTS . '`' ) ); $this->assertSame( 0, (int) $wpdb->get_var( 'SELECT COUNT(*) FROM `' . self::COMMENTMETA . '`' ) ); } public function test_cleanup_preserves_non_stress_comments(): void { global $wpdb; $wpdb->insert( self::COMMENTS, array( 'comment_post_ID' => self::$test_post_id, 'comment_author' => 'Real', 'comment_author_email' => 'real@example.com', 'comment_content' => 'Real comment', 'comment_approved' => '1', ) ); WPDO_Comment_Stress_Tester::create( self::$test_post_id, 3 ); $result = WPDO_Comment_Stress_Tester::cleanup(); $this->assertSame( 3, $result['deleted_comments'] ); $remaining = (int) $wpdb->get_var( 'SELECT COUNT(*) FROM `' . self::COMMENTS . '`' ); $this->assertSame( 1, $remaining ); } public function test_cleanup_idempotent_on_empty(): void { $first = WPDO_Comment_Stress_Tester::cleanup(); $second = WPDO_Comment_Stress_Tester::cleanup(); $this->assertSame( 0, $first['deleted_comments'] ); $this->assertSame( 0, $second['deleted_comments'] ); } // ── State machine ──────────────────────────────────────────────────────── public function test_get_state_returns_empty_when_idle(): void { $this->assertSame( array(), WPDO_Comment_Stress_Tester::get_state() ); } public function test_get_progress_returns_idle_when_no_state(): void { $progress = WPDO_Comment_Stress_Tester::get_progress( false ); $this->assertSame( 'idle', $progress['status'] ); } public function test_start_persists_state_with_running_status(): void { $result = WPDO_Comment_Stress_Tester::start( self::$test_post_id, 10, 'fast', 5 ); $this->assertTrue( $result['ok'], 'start should succeed' ); $state = $result['state']; $this->assertSame( 'running', $state['status'] ); $this->assertSame( self::$test_post_id, $state['post_id'] ); $this->assertSame( 'fast', $state['mode'] ); $this->assertSame( 10, $state['target'] ); $this->assertSame( 5, $state['batch_size'] ); } public function test_start_rejects_unknown_post(): void { $result = WPDO_Comment_Stress_Tester::start( 999999, 10 ); $this->assertFalse( $result['ok'] ); $this->assertStringContainsString( 'unknown_post', $result['error'] ); } public function test_start_rejects_invalid_mode(): void { $result = WPDO_Comment_Stress_Tester::start( self::$test_post_id, 10, 'turbo' ); $this->assertFalse( $result['ok'] ); $this->assertSame( 'invalid mode', $result['error'] ); } public function test_start_rejects_concurrent_run(): void { WPDO_Comment_Stress_Tester::start( self::$test_post_id, 10 ); $result = WPDO_Comment_Stress_Tester::start( self::$test_post_id, 5 ); $this->assertFalse( $result['ok'] ); $this->assertSame( 'already_running', $result['error'] ); } public function test_run_batch_advances_processed_count(): void { WPDO_Comment_Stress_Tester::start( self::$test_post_id, 6, 'fast', 3 ); WPDO_Comment_Stress_Tester::run_batch(); $progress = WPDO_Comment_Stress_Tester::get_progress( false ); $this->assertSame( 3, $progress['processed'] ); $this->assertSame( 1, $progress['batches_done'] ); $this->assertSame( 'running', $progress['status'] ); WPDO_Comment_Stress_Tester::run_batch(); $progress = WPDO_Comment_Stress_Tester::get_progress( false ); $this->assertSame( 6, $progress['processed'] ); $this->assertSame( 'completed', $progress['status'] ); } public function test_cancel_marks_state_as_cancelled(): void { WPDO_Comment_Stress_Tester::start( self::$test_post_id, 100, 'fast', 50 ); $result = WPDO_Comment_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_Comment_Stress_Tester::run_batch(); $state = WPDO_Comment_Stress_Tester::get_state(); $this->assertSame( 'cancelled', $state['status'] ); } public function test_cancel_returns_no_active_job_when_idle(): void { $result = WPDO_Comment_Stress_Tester::cancel(); $this->assertTrue( $result['ok'] ); $this->assertSame( 'no_active_job', $result['message'] ?? '' ); } public function test_get_progress_includes_pct_and_eta_keys(): void { WPDO_Comment_Stress_Tester::start( self::$test_post_id, 10, 'fast', 5 ); WPDO_Comment_Stress_Tester::run_batch(); $progress = WPDO_Comment_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_comment_count', $progress ); $this->assertSame( 50.0, $progress['pct'] ); } public function test_run_benchmark_returns_structured_payload(): void { WPDO_Comment_Stress_Tester::start( self::$test_post_id, 4, 'fast', 4 ); WPDO_Comment_Stress_Tester::run_batch(); $state = WPDO_Comment_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( self::$test_post_id, $state['benchmark']['post_id'] ); } }