d36bb954d1
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
240 lines
8.3 KiB
PHP
240 lines
8.3 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
/**
|
|
* Integration test: WPDO_Post_Migration::copy_legacy_hot_table() (v2.9.5).
|
|
*
|
|
* Verifies non-destructive cutover from legacy `wpdo_hot_<post_type>` table
|
|
* to the new `wp_wpdo_post_<group>` flat table:
|
|
*
|
|
* - copies common columns by name intersection
|
|
* - skips auto_increment id + updated_at columns (let flat manage them)
|
|
* - idempotent (re-run doesn't duplicate; ON DUPLICATE KEY UPDATE)
|
|
* - leaves the legacy table untouched (safety net for v3.0.0 DROP)
|
|
* - verify_legacy_cutover() reports row count + sample mismatches
|
|
*/
|
|
class PostLegacyCutoverTest extends TestCase {
|
|
|
|
private const HOT_TABLE = 'wp_itest_wpdo_hot_hp_listing';
|
|
private const FLAT_TABLE = 'wp_itest_wpdo_post_hp_listing_core';
|
|
|
|
public static function setUpBeforeClass(): void {
|
|
global $wpdb;
|
|
|
|
if ( ! class_exists( 'WPDO_Post_Migration' ) ) {
|
|
require_once WPDO_PLUGIN_DIR . 'includes/migration/class-tmdo-post-migration.php';
|
|
}
|
|
|
|
// Legacy hot table — narrower schema, hp_booking_enabled is hot-only.
|
|
$wpdb->query( 'DROP TABLE IF EXISTS `' . self::HOT_TABLE . '`' );
|
|
$wpdb->query(
|
|
'CREATE TABLE `' . self::HOT_TABLE . '` (
|
|
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
post_id bigint(20) unsigned NOT NULL DEFAULT 0,
|
|
hp_price decimal(10,2) NOT NULL DEFAULT 0.00,
|
|
hp_featured tinyint(1) NOT NULL DEFAULT 0,
|
|
hp_verified tinyint(1) NOT NULL DEFAULT 0,
|
|
hp_expired_time bigint(20) NOT NULL DEFAULT 0,
|
|
hp_featured_time bigint(20) NOT NULL DEFAULT 0,
|
|
updated_at datetime NOT NULL DEFAULT \'0000-00-00 00:00:00\',
|
|
hp_booking_enabled tinyint(1) NOT NULL DEFAULT 0,
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY post_id (post_id)
|
|
) DEFAULT CHARACTER SET utf8mb4'
|
|
);
|
|
|
|
// Flat target — wider schema, includes hp_status/hp_vendor not in hot.
|
|
$wpdb->query( 'DROP TABLE IF EXISTS `' . self::FLAT_TABLE . '`' );
|
|
$wpdb->query(
|
|
'CREATE TABLE `' . self::FLAT_TABLE . '` (
|
|
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
post_id bigint(20) unsigned NOT NULL,
|
|
created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
hp_price decimal(18,6) DEFAULT NULL,
|
|
hp_status varchar(100) DEFAULT NULL,
|
|
hp_featured bigint(20) DEFAULT NULL,
|
|
hp_verified bigint(20) DEFAULT NULL,
|
|
hp_vendor bigint(20) DEFAULT NULL,
|
|
hp_expired_time bigint(20) DEFAULT NULL,
|
|
hp_featured_time bigint(20) DEFAULT NULL,
|
|
hp_view_count bigint(20) DEFAULT NULL,
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY uk_post_id (post_id)
|
|
) DEFAULT CHARACTER SET utf8mb4'
|
|
);
|
|
}
|
|
|
|
public static function tearDownAfterClass(): void {
|
|
global $wpdb;
|
|
$wpdb->query( 'DROP TABLE IF EXISTS `' . self::HOT_TABLE . '`' );
|
|
$wpdb->query( 'DROP TABLE IF EXISTS `' . self::FLAT_TABLE . '`' );
|
|
}
|
|
|
|
protected function setUp(): void {
|
|
global $wpdb;
|
|
$wpdb->query( 'TRUNCATE TABLE `' . self::HOT_TABLE . '`' );
|
|
$wpdb->query( 'TRUNCATE TABLE `' . self::FLAT_TABLE . '`' );
|
|
}
|
|
|
|
private function seed_hot( int $post_id, array $cols ): void {
|
|
global $wpdb;
|
|
$wpdb->insert( self::HOT_TABLE, array_merge( array( 'post_id' => $post_id ), $cols ) );
|
|
}
|
|
|
|
// ── copy_legacy_hot_table() ──────────────────────────────────────────────
|
|
|
|
public function test_copy_legacy_hot_table_copies_all_rows(): void {
|
|
// Seed 5 rows.
|
|
for ( $i = 1; $i <= 5; $i++ ) {
|
|
$this->seed_hot( 100 + $i, array(
|
|
'hp_price' => 50.00 + $i,
|
|
'hp_featured' => $i % 2,
|
|
'hp_verified' => 1,
|
|
'hp_expired_time' => 9999999 + $i,
|
|
'hp_featured_time' => 0,
|
|
) );
|
|
}
|
|
|
|
$result = WPDO_Post_Migration::copy_legacy_hot_table(
|
|
'hp_listing',
|
|
self::HOT_TABLE,
|
|
self::FLAT_TABLE
|
|
);
|
|
|
|
$this->assertSame( 5, $result['copied'] );
|
|
|
|
global $wpdb;
|
|
$flat_count = (int) $wpdb->get_var( 'SELECT COUNT(*) FROM `' . self::FLAT_TABLE . '`' );
|
|
$this->assertSame( 5, $flat_count );
|
|
|
|
// Verify a row's data round-trips.
|
|
$row = $wpdb->get_row( 'SELECT hp_price, hp_featured, hp_verified, hp_expired_time FROM `' . self::FLAT_TABLE . '` WHERE post_id = 103', ARRAY_A );
|
|
$this->assertSame( '53.000000', $row['hp_price'] );
|
|
$this->assertSame( '1', $row['hp_featured'] ); // 3 % 2 = 1
|
|
$this->assertSame( '1', $row['hp_verified'] );
|
|
$this->assertSame( '10000002', $row['hp_expired_time'] );
|
|
}
|
|
|
|
public function test_copy_skips_id_and_updated_at_columns(): void {
|
|
$this->seed_hot( 200, array(
|
|
'hp_price' => 99.99,
|
|
'hp_featured' => 0,
|
|
'hp_verified' => 1,
|
|
'hp_expired_time' => 0,
|
|
'hp_featured_time' => 0,
|
|
) );
|
|
|
|
WPDO_Post_Migration::copy_legacy_hot_table(
|
|
'hp_listing',
|
|
self::HOT_TABLE,
|
|
self::FLAT_TABLE
|
|
);
|
|
|
|
global $wpdb;
|
|
// Flat row's id should be auto-assigned (not the hot row's id).
|
|
// Flat row's updated_at should be CURRENT_TIMESTAMP (not 0000-00-00).
|
|
$row = $wpdb->get_row( 'SELECT id, updated_at FROM `' . self::FLAT_TABLE . '` WHERE post_id = 200', ARRAY_A );
|
|
$this->assertNotEmpty( $row['updated_at'] );
|
|
$this->assertNotEquals( '0000-00-00 00:00:00', $row['updated_at'] );
|
|
}
|
|
|
|
public function test_copy_legacy_hot_table_is_idempotent(): void {
|
|
$this->seed_hot( 300, array(
|
|
'hp_price' => 10.00,
|
|
'hp_featured' => 0,
|
|
'hp_verified' => 1,
|
|
'hp_expired_time' => 0,
|
|
'hp_featured_time' => 0,
|
|
) );
|
|
|
|
WPDO_Post_Migration::copy_legacy_hot_table( 'hp_listing', self::HOT_TABLE, self::FLAT_TABLE );
|
|
WPDO_Post_Migration::copy_legacy_hot_table( 'hp_listing', self::HOT_TABLE, self::FLAT_TABLE );
|
|
|
|
global $wpdb;
|
|
$count = (int) $wpdb->get_var( 'SELECT COUNT(*) FROM `' . self::FLAT_TABLE . '`' );
|
|
$this->assertSame( 1, $count, 'Re-running copy is idempotent — UPSERT, no duplicate.' );
|
|
}
|
|
|
|
public function test_copy_does_not_modify_legacy_hot_table(): void {
|
|
$this->seed_hot( 400, array(
|
|
'hp_price' => 25.00,
|
|
'hp_featured' => 0,
|
|
'hp_verified' => 1,
|
|
'hp_expired_time' => 0,
|
|
'hp_featured_time' => 0,
|
|
) );
|
|
|
|
global $wpdb;
|
|
$before = $wpdb->get_results( 'SELECT * FROM `' . self::HOT_TABLE . '` ORDER BY id', ARRAY_A );
|
|
|
|
WPDO_Post_Migration::copy_legacy_hot_table( 'hp_listing', self::HOT_TABLE, self::FLAT_TABLE );
|
|
|
|
$after = $wpdb->get_results( 'SELECT * FROM `' . self::HOT_TABLE . '` ORDER BY id', ARRAY_A );
|
|
$this->assertEquals( $before, $after, 'Legacy hot table must remain untouched (safety net for v3.0.0).' );
|
|
}
|
|
|
|
public function test_copy_returns_zero_when_hot_table_empty(): void {
|
|
$result = WPDO_Post_Migration::copy_legacy_hot_table(
|
|
'hp_listing',
|
|
self::HOT_TABLE,
|
|
self::FLAT_TABLE
|
|
);
|
|
$this->assertSame( 0, $result['copied'] );
|
|
}
|
|
|
|
public function test_copy_throws_when_hot_table_missing(): void {
|
|
$this->expectException( RuntimeException::class );
|
|
WPDO_Post_Migration::copy_legacy_hot_table(
|
|
'hp_listing',
|
|
'wp_itest_nonexistent_hot',
|
|
self::FLAT_TABLE
|
|
);
|
|
}
|
|
|
|
// ── verify_legacy_cutover() ──────────────────────────────────────────────
|
|
|
|
public function test_verify_reports_match_when_counts_equal(): void {
|
|
for ( $i = 1; $i <= 3; $i++ ) {
|
|
$this->seed_hot( 500 + $i, array(
|
|
'hp_price' => $i * 10,
|
|
'hp_featured' => 0,
|
|
'hp_verified' => 1,
|
|
'hp_expired_time' => 0,
|
|
'hp_featured_time' => 0,
|
|
) );
|
|
}
|
|
|
|
WPDO_Post_Migration::copy_legacy_hot_table( 'hp_listing', self::HOT_TABLE, self::FLAT_TABLE );
|
|
|
|
$verify = WPDO_Post_Migration::verify_legacy_cutover( self::HOT_TABLE, self::FLAT_TABLE );
|
|
|
|
$this->assertSame( 3, $verify['hot_rows'] );
|
|
$this->assertSame( 3, $verify['flat_rows'] );
|
|
$this->assertSame( 0, $verify['mismatched_rows'] );
|
|
$this->assertTrue( $verify['ok'] );
|
|
}
|
|
|
|
public function test_verify_reports_mismatch_when_flat_lags_hot(): void {
|
|
// Seed hot with 3 rows.
|
|
for ( $i = 1; $i <= 3; $i++ ) {
|
|
$this->seed_hot( 600 + $i, array(
|
|
'hp_price' => $i * 10,
|
|
'hp_featured' => 0,
|
|
'hp_verified' => 1,
|
|
'hp_expired_time' => 0,
|
|
'hp_featured_time' => 0,
|
|
) );
|
|
}
|
|
// Don't run copy — flat stays empty.
|
|
|
|
$verify = WPDO_Post_Migration::verify_legacy_cutover( self::HOT_TABLE, self::FLAT_TABLE );
|
|
|
|
$this->assertSame( 3, $verify['hot_rows'] );
|
|
$this->assertSame( 0, $verify['flat_rows'] );
|
|
$this->assertFalse( $verify['ok'] );
|
|
}
|
|
}
|