151a14a7e8
- CREATE TABLE wpdo_warm 的 meta_key varchar(255)→varchar(191), KEY idx_post_meta → UNIQUE KEY ui_post_meta:沒有這個唯一鍵, ON DUPLICATE KEY UPDATE 不會觸發,會不斷 INSERT 重複列。 (既有站台的 ALTER 遷移原本就在 installer:1329,只有 CREATE 落後) - Zone_Warm::set() 由 SELECT→update/insert 改為 TMDO_DB::upsert() - 新增 Zone_Warm::increment():CAST(COALESCE(meta_value,0) AS SIGNED)+N 原子計數,取代 get()+set() 的 read-modify-write race(A v3.3.3) - ZoneWarmTest stub 與 ZoneWarmIntegrationTest 建表同步適配 unit 379 / integration 398 GREEN Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
170 lines
6.3 KiB
PHP
170 lines
6.3 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
/**
|
|
* Integration tests for WPDO_Zone_Warm against real MariaDB.
|
|
*
|
|
* Creates a dedicated test table (wp_itest_wpdo_warm) so the real
|
|
* production warm table is never touched.
|
|
*/
|
|
class ZoneWarmIntegrationTest extends TestCase {
|
|
|
|
private const TABLE = 'wp_itest_wpdo_warm';
|
|
|
|
// ── Fixture lifecycle ─────────────────────────────────────────────────
|
|
|
|
public static function setUpBeforeClass(): void {
|
|
global $wpdb;
|
|
// DROP + CREATE ensures clean schema even after interrupted prior runs.
|
|
$wpdb->query( 'DROP TABLE IF EXISTS `' . self::TABLE . '`' );
|
|
$wpdb->query(
|
|
'CREATE TABLE `' . self::TABLE . '` (
|
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
`post_id` bigint(20) unsigned NOT NULL DEFAULT 0,
|
|
`meta_key` varchar(255) NOT NULL DEFAULT \'\',
|
|
`meta_value` longtext DEFAULT NULL,
|
|
`expires_at` datetime DEFAULT NULL,
|
|
`created_at` datetime NOT NULL DEFAULT \'0000-00-00 00:00:00\',
|
|
PRIMARY KEY (`id`),
|
|
UNIQUE KEY `ui_post_meta` (`post_id`, `meta_key`),
|
|
KEY `expires_at` (`expires_at`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4'
|
|
);
|
|
}
|
|
|
|
public static function tearDownAfterClass(): void {
|
|
global $wpdb;
|
|
$wpdb->query( 'DROP TABLE IF EXISTS `' . self::TABLE . '`' );
|
|
}
|
|
|
|
protected function setUp(): void {
|
|
global $wpdb;
|
|
$wpdb->query( 'TRUNCATE TABLE `' . self::TABLE . '`' );
|
|
}
|
|
|
|
// ── set / get ────────────────────────────────────────────────────────
|
|
|
|
public function test_set_and_get_basic(): void {
|
|
WPDO_Zone_Warm::set( 1, 'test_key', 'hello' );
|
|
$this->assertSame( 'hello', WPDO_Zone_Warm::get( 1, 'test_key' ) );
|
|
}
|
|
|
|
public function test_get_returns_null_for_missing_key(): void {
|
|
$this->assertNull( WPDO_Zone_Warm::get( 9999, 'no_such_key' ) );
|
|
}
|
|
|
|
public function test_set_overwrites_existing_value(): void {
|
|
WPDO_Zone_Warm::set( 2, 'counter', '1' );
|
|
WPDO_Zone_Warm::set( 2, 'counter', '5' );
|
|
$this->assertSame( '5', WPDO_Zone_Warm::get( 2, 'counter' ) );
|
|
}
|
|
|
|
// ── TTL / expiry ─────────────────────────────────────────────────────
|
|
|
|
public function test_set_with_future_ttl_is_readable(): void {
|
|
WPDO_Zone_Warm::set( 3, 'flag', 'active', 3600 ); // expires in 1 hour
|
|
$this->assertSame( 'active', WPDO_Zone_Warm::get( 3, 'flag' ) );
|
|
}
|
|
|
|
public function test_expired_entry_returns_null(): void {
|
|
global $wpdb;
|
|
// Insert directly with a past expiry timestamp.
|
|
$wpdb->query(
|
|
"INSERT INTO `" . self::TABLE . "` (post_id, meta_key, meta_value, expires_at, created_at)
|
|
VALUES (4, 'old_flag', 'gone', '2000-01-01 00:00:00', '2000-01-01 00:00:00')"
|
|
);
|
|
$this->assertNull( WPDO_Zone_Warm::get( 4, 'old_flag' ) );
|
|
}
|
|
|
|
public function test_null_ttl_entry_never_expires(): void {
|
|
WPDO_Zone_Warm::set( 5, 'permanent', 'stays', null );
|
|
$this->assertSame( 'stays', WPDO_Zone_Warm::get( 5, 'permanent' ) );
|
|
}
|
|
|
|
// ── delete ───────────────────────────────────────────────────────────
|
|
|
|
public function test_delete_removes_specific_key(): void {
|
|
WPDO_Zone_Warm::set( 6, 'key_a', 'alpha' );
|
|
WPDO_Zone_Warm::set( 6, 'key_b', 'beta' );
|
|
|
|
WPDO_Zone_Warm::delete( 6, 'key_a' );
|
|
|
|
$this->assertNull( WPDO_Zone_Warm::get( 6, 'key_a' ) );
|
|
$this->assertSame( 'beta', WPDO_Zone_Warm::get( 6, 'key_b' ) );
|
|
}
|
|
|
|
public function test_delete_all_removes_all_keys_for_post(): void {
|
|
WPDO_Zone_Warm::set( 7, 'x', '1' );
|
|
WPDO_Zone_Warm::set( 7, 'y', '2' );
|
|
WPDO_Zone_Warm::set( 7, 'z', '3' );
|
|
|
|
WPDO_Zone_Warm::delete_all( 7 );
|
|
|
|
$this->assertNull( WPDO_Zone_Warm::get( 7, 'x' ) );
|
|
$this->assertNull( WPDO_Zone_Warm::get( 7, 'y' ) );
|
|
$this->assertNull( WPDO_Zone_Warm::get( 7, 'z' ) );
|
|
}
|
|
|
|
public function test_delete_all_does_not_affect_other_posts(): void {
|
|
WPDO_Zone_Warm::set( 8, 'shared_key', 'post_8' );
|
|
WPDO_Zone_Warm::set( 9, 'shared_key', 'post_9' );
|
|
|
|
WPDO_Zone_Warm::delete_all( 8 );
|
|
|
|
$this->assertNull( WPDO_Zone_Warm::get( 8, 'shared_key' ) );
|
|
$this->assertSame( 'post_9', WPDO_Zone_Warm::get( 9, 'shared_key' ) );
|
|
}
|
|
|
|
// ── purge_expired ────────────────────────────────────────────────────
|
|
|
|
public function test_purge_expired_removes_stale_entries(): void {
|
|
global $wpdb;
|
|
// One expired entry.
|
|
$wpdb->query(
|
|
"INSERT INTO `" . self::TABLE . "` (post_id, meta_key, meta_value, expires_at, created_at)
|
|
VALUES (10, 'stale', 'gone', '2000-01-01 00:00:00', '2000-01-01 00:00:00')"
|
|
);
|
|
// One valid entry.
|
|
WPDO_Zone_Warm::set( 10, 'fresh', 'keep', 3600 );
|
|
|
|
$deleted = WPDO_Zone_Warm::purge_expired();
|
|
|
|
$this->assertSame( 1, $deleted );
|
|
$this->assertNull( WPDO_Zone_Warm::get( 10, 'stale' ) );
|
|
$this->assertSame( 'keep', WPDO_Zone_Warm::get( 10, 'fresh' ) );
|
|
}
|
|
|
|
public function test_purge_expired_returns_zero_when_nothing_stale(): void {
|
|
WPDO_Zone_Warm::set( 11, 'live', 'value', 3600 );
|
|
$this->assertSame( 0, WPDO_Zone_Warm::purge_expired() );
|
|
}
|
|
|
|
// ── get_all ──────────────────────────────────────────────────────────
|
|
|
|
public function test_get_all_returns_all_valid_keys_for_post(): void {
|
|
WPDO_Zone_Warm::set( 12, 'ka', 'va' );
|
|
WPDO_Zone_Warm::set( 12, 'kb', 'vb' );
|
|
|
|
$all = WPDO_Zone_Warm::get_all( 12 );
|
|
$this->assertArrayHasKey( 'ka', $all );
|
|
$this->assertArrayHasKey( 'kb', $all );
|
|
$this->assertSame( 'va', $all['ka'] );
|
|
$this->assertSame( 'vb', $all['kb'] );
|
|
}
|
|
|
|
public function test_get_all_excludes_expired_entries(): void {
|
|
global $wpdb;
|
|
WPDO_Zone_Warm::set( 13, 'live', 'yes' );
|
|
$wpdb->query(
|
|
"INSERT INTO `" . self::TABLE . "` (post_id, meta_key, meta_value, expires_at, created_at)
|
|
VALUES (13, 'dead', 'no', '2000-01-01 00:00:00', '2000-01-01 00:00:00')"
|
|
);
|
|
|
|
$all = WPDO_Zone_Warm::get_all( 13 );
|
|
$this->assertArrayHasKey( 'live', $all );
|
|
$this->assertArrayNotHasKey( 'dead', $all );
|
|
}
|
|
}
|