59c9b698b7
從 wp-data-optimizer v3.4.6 移植 5 個 integration 測試檔,並新增 tests/integration/bootstrap.php(複用核心的 integration bootstrap,不重複 與 WP stub)+ phpunit-integration.xml + CI integration job。
161 lines
4.8 KiB
PHP
161 lines
4.8 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
/**
|
|
* Integration tests for WPDO_Listing_Meta_Interceptor — PR-3 R-2 + P-C1 fixes.
|
|
*
|
|
* Verifies:
|
|
* 1. R-2: Interceptor SKIPS hook registration when hpct_listing_meta is missing
|
|
* (prevents the "wp_hpct_listing_meta doesn't exist" cascading errors that
|
|
* forced 2meet-infocards to bypass the interceptor in production).
|
|
* 2. P-C1: upsert_meta() uses 1 SQL round-trip via WPDO_DB::upsert().
|
|
*
|
|
* @covers WPDO_Listing_Meta_Interceptor
|
|
*/
|
|
class ListingMetaInterceptorTest extends TestCase {
|
|
|
|
/**
|
|
* R-2: When hpct_listing_meta table is missing, register_hooks() must skip
|
|
* gracefully and write a single explanatory error log entry.
|
|
*
|
|
* @runInSeparateProcess
|
|
*/
|
|
public function test_register_hooks_skips_when_table_missing(): void {
|
|
global $wpdb;
|
|
|
|
$wpdb->query( "DROP TABLE IF EXISTS `{$wpdb->prefix}hpct_listing_meta`" );
|
|
|
|
// Simulate HPCT_Core being present — register_hooks() only logs the skip
|
|
// when HPCT is loaded but its table is missing (genuine inconsistency).
|
|
if ( ! class_exists( 'HPCT_Core' ) ) {
|
|
// phpcs:ignore Generic.Commenting.InlineComment.InvalidEndChar -- runtime stub
|
|
eval( 'class HPCT_Core {}' ); // @phpcs:ignore
|
|
}
|
|
|
|
// Ensure wpdo_errors exists for the skip log; harmless if pre-created.
|
|
$wpdb->query(
|
|
"CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}wpdo_errors` (
|
|
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
module varchar(50) NOT NULL DEFAULT '',
|
|
zone varchar(10) NOT NULL DEFAULT '',
|
|
hook varchar(255) NOT NULL DEFAULT '',
|
|
message longtext NOT NULL,
|
|
context longtext,
|
|
created_at datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
|
PRIMARY KEY (id),
|
|
KEY idx_module (module)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"
|
|
);
|
|
|
|
// Snapshot pre-call count of skip messages.
|
|
$pre = (int) $wpdb->get_var(
|
|
$wpdb->prepare(
|
|
"SELECT COUNT(*) FROM `{$wpdb->prefix}wpdo_errors` WHERE module = %s AND hook = %s",
|
|
'listing_meta',
|
|
'register_hooks'
|
|
)
|
|
);
|
|
|
|
$interceptor = new WPDO_Listing_Meta_Interceptor();
|
|
$interceptor->register_hooks();
|
|
|
|
$post = (int) $wpdb->get_var(
|
|
$wpdb->prepare(
|
|
"SELECT COUNT(*) FROM `{$wpdb->prefix}wpdo_errors` WHERE module = %s AND hook = %s",
|
|
'listing_meta',
|
|
'register_hooks'
|
|
)
|
|
);
|
|
$this->assertSame( $pre + 1, $post, 'Expected exactly one new skip message after register_hooks()' );
|
|
}
|
|
|
|
/**
|
|
* P-C1: WPDO_DB::upsert() must produce an INSERT ... ON DUPLICATE KEY UPDATE
|
|
* statement (single round-trip), and writes must succeed via the composite
|
|
* unique key (listing_id, meta_key).
|
|
*
|
|
* @runInSeparateProcess
|
|
*/
|
|
public function test_upsert_uses_composite_unique_key(): void {
|
|
global $wpdb;
|
|
|
|
$table = $wpdb->prefix . 'hpct_listing_meta';
|
|
|
|
// Clean slate.
|
|
$wpdb->query( "DROP TABLE IF EXISTS `{$table}`" );
|
|
$wpdb->query(
|
|
"CREATE TABLE `{$table}` (
|
|
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
listing_id bigint(20) unsigned NOT NULL DEFAULT 0,
|
|
meta_key varchar(255) NOT NULL DEFAULT '',
|
|
meta_value longtext,
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY ui_listing_meta (listing_id, meta_key(191))
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"
|
|
);
|
|
|
|
// First upsert: INSERT.
|
|
$result1 = WPDO_DB::upsert(
|
|
$table,
|
|
array(
|
|
'listing_id' => 4242,
|
|
'meta_key' => 'hp_price',
|
|
'meta_value' => '100.00',
|
|
),
|
|
array( 'meta_value' ),
|
|
array( 'listing_id', 'meta_key' ),
|
|
array( '%d', '%s', '%s' )
|
|
);
|
|
$this->assertNotFalse( $result1 );
|
|
|
|
// Second upsert: UPDATE via the composite key.
|
|
$result2 = WPDO_DB::upsert(
|
|
$table,
|
|
array(
|
|
'listing_id' => 4242,
|
|
'meta_key' => 'hp_price',
|
|
'meta_value' => '250.50',
|
|
),
|
|
array( 'meta_value' ),
|
|
array( 'listing_id', 'meta_key' ),
|
|
array( '%d', '%s', '%s' )
|
|
);
|
|
$this->assertNotFalse( $result2 );
|
|
|
|
// Verify only one row exists for (4242, 'hp_price') with the latest value.
|
|
$rows = $wpdb->get_results(
|
|
$wpdb->prepare(
|
|
"SELECT meta_value FROM `{$table}` WHERE listing_id = %d AND meta_key = %s",
|
|
4242,
|
|
'hp_price'
|
|
),
|
|
ARRAY_A
|
|
);
|
|
$this->assertCount( 1, $rows, 'Composite UNIQUE must collapse two upserts into a single row' );
|
|
$this->assertSame( '250.50', $rows[0]['meta_value'] );
|
|
|
|
// Cleanup.
|
|
$wpdb->query( "DROP TABLE IF EXISTS `{$table}`" );
|
|
}
|
|
|
|
/**
|
|
* Verify table_exists() returns false when table missing, true after CREATE.
|
|
*
|
|
* @runInSeparateProcess
|
|
*/
|
|
public function test_table_exists_detection(): void {
|
|
global $wpdb;
|
|
|
|
$wpdb->query( "DROP TABLE IF EXISTS `{$wpdb->prefix}hpct_listing_meta`" );
|
|
|
|
// Use reflection to invoke private static.
|
|
$ref = new ReflectionClass( WPDO_Listing_Meta_Interceptor::class );
|
|
$method = $ref->getMethod( 'table_exists' );
|
|
$method->setAccessible( true );
|
|
|
|
$this->assertFalse( $method->invoke( null ), 'table_exists must return false when table missing' );
|
|
}
|
|
}
|