Files
2meet-data-optimizer/tests/integration/ZoneColdIntegrationTest.php
T
wpdev d36bb954d1 chore: initial snapshot of 2meet-data-optimizer v0.1.0
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
2026-07-31 05:06:36 +08:00

224 lines
9.6 KiB
PHP

<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
/**
* Integration tests for WPDO_Zone_Cold against real MariaDB.
*
* Creates a dedicated cold table (wp_itest_wpdo_cold_itest) to exercise all
* Zone C operations: set / get, set_many / get_blob, remove, delete, and
* Object Cache invalidation.
*
* post_type = 'itest' maps to table prefix wp_itest_wpdo_cold_itest.
*/
class ZoneColdIntegrationTest extends TestCase {
private const POST_TYPE = 'itest';
/** Derived at runtime: $wpdb->prefix . 'wpdo_cold_itest' */
private static string $table;
// ── Fixture lifecycle ─────────────────────────────────────────────────────
public static function setUpBeforeClass(): void {
global $wpdb;
self::$table = $wpdb->prefix . 'wpdo_cold_' . self::POST_TYPE;
$wpdb->query(
"CREATE TABLE IF NOT EXISTS `" . self::$table . "` (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
post_id BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
data LONGTEXT NOT NULL,
updated_at DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (id),
UNIQUE KEY ui_post_id (post_id)
) 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 . "`" );
$GLOBALS['_wp_cache'] = [];
}
// ── set / get ─────────────────────────────────────────────────────────────
public function test_set_and_get_single_field(): void {
WPDO_Zone_Cold::set( 100, self::POST_TYPE, 'hp_description', 'Hello World' );
$val = WPDO_Zone_Cold::get( 100, self::POST_TYPE, 'hp_description' );
$this->assertSame( 'Hello World', $val );
}
public function test_get_returns_null_for_missing_key(): void {
WPDO_Zone_Cold::set( 101, self::POST_TYPE, 'hp_description', 'present' );
$val = WPDO_Zone_Cold::get( 101, self::POST_TYPE, 'missing_key' );
$this->assertNull( $val );
}
public function test_get_returns_null_for_missing_post(): void {
$val = WPDO_Zone_Cold::get( 9999, self::POST_TYPE, 'hp_description' );
$this->assertNull( $val );
}
public function test_set_overwrites_existing_value(): void {
WPDO_Zone_Cold::set( 102, self::POST_TYPE, 'hp_website', 'http://old.example.com' );
WPDO_Zone_Cold::set( 102, self::POST_TYPE, 'hp_website', 'http://new.example.com' );
$val = WPDO_Zone_Cold::get( 102, self::POST_TYPE, 'hp_website' );
$this->assertSame( 'http://new.example.com', $val );
}
public function test_set_preserves_other_keys_in_blob(): void {
WPDO_Zone_Cold::set( 103, self::POST_TYPE, 'hp_description', 'Keep me' );
WPDO_Zone_Cold::set( 103, self::POST_TYPE, 'hp_website', 'https://keep.example.com' );
// Update only one key.
WPDO_Zone_Cold::set( 103, self::POST_TYPE, 'hp_website', 'https://updated.example.com' );
$this->assertSame( 'Keep me', WPDO_Zone_Cold::get( 103, self::POST_TYPE, 'hp_description' ) );
$this->assertSame( 'https://updated.example.com', WPDO_Zone_Cold::get( 103, self::POST_TYPE, 'hp_website' ) );
}
// ── set_many / get_blob ───────────────────────────────────────────────────
public function test_set_many_stores_multiple_fields(): void {
WPDO_Zone_Cold::set_many( 200, self::POST_TYPE, [
'hp_description' => 'A great listing',
'hp_website' => 'https://example.com',
'hp_facebook' => 'https://facebook.com/test',
] );
$this->assertSame( 'A great listing', WPDO_Zone_Cold::get( 200, self::POST_TYPE, 'hp_description' ) );
$this->assertSame( 'https://example.com', WPDO_Zone_Cold::get( 200, self::POST_TYPE, 'hp_website' ) );
$this->assertSame( 'https://facebook.com/test', WPDO_Zone_Cold::get( 200, self::POST_TYPE, 'hp_facebook' ) );
}
public function test_get_blob_returns_all_fields(): void {
WPDO_Zone_Cold::set_many( 201, self::POST_TYPE, [
'hp_description' => 'Blob test',
'hp_website' => 'https://blob.example.com',
] );
$blob = WPDO_Zone_Cold::get_blob( 201, self::POST_TYPE );
$this->assertIsArray( $blob );
$this->assertArrayHasKey( 'hp_description', $blob );
$this->assertArrayHasKey( 'hp_website', $blob );
$this->assertSame( 'Blob test', $blob['hp_description'] );
$this->assertSame( 'https://blob.example.com', $blob['hp_website'] );
}
public function test_get_blob_returns_empty_array_for_missing_post(): void {
$blob = WPDO_Zone_Cold::get_blob( 9998, self::POST_TYPE );
$this->assertIsArray( $blob );
$this->assertEmpty( $blob );
}
public function test_set_many_merges_with_existing_blob(): void {
WPDO_Zone_Cold::set_many( 202, self::POST_TYPE, [ 'hp_description' => 'First' ] );
WPDO_Zone_Cold::set_many( 202, self::POST_TYPE, [ 'hp_website' => 'https://merge.example.com' ] );
$this->assertSame( 'First', WPDO_Zone_Cold::get( 202, self::POST_TYPE, 'hp_description' ) );
$this->assertSame( 'https://merge.example.com', WPDO_Zone_Cold::get( 202, self::POST_TYPE, 'hp_website' ) );
}
// ── remove ────────────────────────────────────────────────────────────────
public function test_remove_key_from_blob(): void {
WPDO_Zone_Cold::set_many( 300, self::POST_TYPE, [
'hp_description' => 'Keep me',
'hp_website' => 'https://remove.example.com',
] );
WPDO_Zone_Cold::remove( 300, self::POST_TYPE, 'hp_website' );
$this->assertSame( 'Keep me', WPDO_Zone_Cold::get( 300, self::POST_TYPE, 'hp_description' ) );
$this->assertNull( WPDO_Zone_Cold::get( 300, self::POST_TYPE, 'hp_website' ) );
}
public function test_remove_nonexistent_key_does_not_error(): void {
WPDO_Zone_Cold::set( 301, self::POST_TYPE, 'hp_description', 'Safe' );
WPDO_Zone_Cold::remove( 301, self::POST_TYPE, 'no_such_key' );
// Original key should still be intact.
$this->assertSame( 'Safe', WPDO_Zone_Cold::get( 301, self::POST_TYPE, 'hp_description' ) );
}
// ── delete ────────────────────────────────────────────────────────────────
public function test_delete_removes_row(): void {
global $wpdb;
WPDO_Zone_Cold::set( 400, self::POST_TYPE, 'hp_description', 'To be deleted' );
WPDO_Zone_Cold::delete( 400, self::POST_TYPE );
$count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `" . self::$table . "` WHERE post_id = 400" );
$this->assertSame( 0, $count );
$this->assertNull( WPDO_Zone_Cold::get( 400, self::POST_TYPE, 'hp_description' ) );
}
public function test_delete_nonexistent_post_does_not_error(): void {
WPDO_Zone_Cold::delete( 9997, self::POST_TYPE );
$this->assertTrue( true ); // Must not throw.
}
// ── Object Cache ──────────────────────────────────────────────────────────
public function test_get_blob_populates_object_cache(): void {
WPDO_Zone_Cold::set( 500, self::POST_TYPE, 'hp_description', 'Cached value' );
// Clear cache to force a DB read on the next call.
$GLOBALS['_wp_cache'] = [];
// First get: reads from DB, warms the cache.
$val = WPDO_Zone_Cold::get( 500, self::POST_TYPE, 'hp_description' );
$this->assertSame( 'Cached value', $val );
// Cache entry must now exist.
$cached = wp_cache_get( 'cold_500', 'wpdo_cold_itest' );
$this->assertIsArray( $cached );
$this->assertSame( 'Cached value', $cached['hp_description'] );
}
public function test_set_invalidates_object_cache(): void {
WPDO_Zone_Cold::set( 501, self::POST_TYPE, 'hp_description', 'Original' );
// Warm the cache by reading once.
WPDO_Zone_Cold::get( 501, self::POST_TYPE, 'hp_description' );
$this->assertNotFalse( wp_cache_get( 'cold_501', 'wpdo_cold_itest' ) );
// Write a new value — must invalidate the cached blob.
WPDO_Zone_Cold::set( 501, self::POST_TYPE, 'hp_description', 'Updated' );
$this->assertFalse( wp_cache_get( 'cold_501', 'wpdo_cold_itest' ) );
// Subsequent read must return the updated value (from DB).
$val = WPDO_Zone_Cold::get( 501, self::POST_TYPE, 'hp_description' );
$this->assertSame( 'Updated', $val );
}
public function test_delete_invalidates_object_cache(): void {
WPDO_Zone_Cold::set( 502, self::POST_TYPE, 'hp_description', 'Will be deleted' );
// Warm the cache.
WPDO_Zone_Cold::get( 502, self::POST_TYPE, 'hp_description' );
// Delete — must clear cache.
WPDO_Zone_Cold::delete( 502, self::POST_TYPE );
$this->assertFalse( wp_cache_get( 'cold_502', 'wpdo_cold_itest' ) );
}
// ── isolation ─────────────────────────────────────────────────────────────
public function test_different_post_ids_are_independent(): void {
WPDO_Zone_Cold::set( 600, self::POST_TYPE, 'hp_description', 'Post 600' );
WPDO_Zone_Cold::set( 601, self::POST_TYPE, 'hp_description', 'Post 601' );
$this->assertSame( 'Post 600', WPDO_Zone_Cold::get( 600, self::POST_TYPE, 'hp_description' ) );
$this->assertSame( 'Post 601', WPDO_Zone_Cold::get( 601, self::POST_TYPE, 'hp_description' ) );
}
}