test: 加入 integration 測試套件(連真實 MariaDB)
從 wp-data-optimizer v3.4.6 移植 5 個 integration 測試檔,並新增 tests/integration/bootstrap.php(複用核心的 integration bootstrap,不重複 與 WP stub)+ phpunit-integration.xml + CI integration job。
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
<?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' );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user