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
224 lines
9.6 KiB
PHP
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' ) );
|
|
}
|
|
}
|