Files
2meet-data-optimizer/tests/integration/PostQueryRouterTest.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

246 lines
7.3 KiB
PHP

<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
/**
* Integration test: WPDO_Post_Query_Router (v2.10.1).
*
* Verifies meta_query rewriting when post mode is reads_from_flat (i.e.
* shadow_read or aeav_only). The router strips clauses targeting registered
* Entity Registry keys, JOINs the corresponding flat table, and appends
* WHERE conditions in SQL.
*
* 🔒 Frozen contract:
* - mode=disabled → router pass-through (zero modification)
* - mode=dual_write → router pass-through (wp_postmeta still source-of-truth)
* - mode=shadow_read → router rewrites (flat is read-replica candidate)
* - mode=aeav_only → router rewrites (flat is source-of-truth)
*/
class PostQueryRouterTest extends TestCase {
public static function setUpBeforeClass(): void {
$plugin_dir = WPDO_PLUGIN_DIR;
foreach ( array(
'includes/adapters/interface-entity-adapter.php',
'includes/engine/class-tmdo-entity-registry.php',
'includes/engine/class-tmdo-mode-manager.php',
'includes/engine/class-tmdo-schema-manager.php',
'includes/adapters/class-tmdo-adapter-post.php',
'includes/integrations/class-tmdo-post-fields.php',
'includes/query/class-tmdo-post-query-router.php',
) as $rel ) {
$file = $plugin_dir . $rel;
if ( file_exists( $file ) ) {
require_once $file;
}
}
WPDO_Entity_Registry::init();
WPDO_Entity_Registry::register_adapter( 'post', new WPDO_Adapter_Post() );
WPDO_Post_Fields::register_entity_fields();
}
public static function tearDownAfterClass(): void {
$ref = new ReflectionClass( WPDO_Mode_Manager::class );
$cache = $ref->getProperty( 'cache' );
$cache->setAccessible( true );
$cache->setValue( null, null );
WPDO_Entity_Registry::init();
}
private function set_post_mode( string $mode ): void {
$ref = new ReflectionClass( WPDO_Mode_Manager::class );
$cache = $ref->getProperty( 'cache' );
$cache->setAccessible( true );
$cache->setValue( null, array(
'post' => $mode,
'user' => 'aeav_only',
'term' => 'dual_write',
'comment' => 'dual_write',
) );
}
private function make_query( array $vars ): WP_Query {
$q = new WP_Query();
foreach ( $vars as $k => $v ) {
$q->set( $k, $v );
}
return $q;
}
// ── pre_get_posts gate (mode-aware) ───────────────────────────────────────
public function test_pass_through_when_mode_disabled(): void {
$this->set_post_mode( 'disabled' );
$router = new WPDO_Post_Query_Router();
$query = $this->make_query( array(
'post_type' => 'product',
'meta_query' => array(
array( 'key' => '_price', 'value' => '50', 'compare' => '>=' ),
),
) );
$original = $query->get( 'meta_query' );
$router->pre_get_posts( $query );
$this->assertSame(
$original,
$query->get( 'meta_query' ),
'mode=disabled: meta_query must be untouched.'
);
$this->assertSame( '', $query->get( 'wpdo_post_clauses' ) );
}
public function test_pass_through_when_mode_dual_write(): void {
$this->set_post_mode( 'dual_write' );
$router = new WPDO_Post_Query_Router();
$query = $this->make_query( array(
'post_type' => 'product',
'meta_query' => array(
array( 'key' => '_price', 'value' => '50', 'compare' => '>=' ),
),
) );
$original = $query->get( 'meta_query' );
$router->pre_get_posts( $query );
$this->assertSame(
$original,
$query->get( 'meta_query' ),
'mode=dual_write: wp_postmeta is still source-of-truth, no rewrite.'
);
}
// ── pre_get_posts rewrite (mode=aeav_only) ───────────────────────────────
public function test_rewrites_meta_query_when_mode_aeav_only(): void {
$this->set_post_mode( 'aeav_only' );
$router = new WPDO_Post_Query_Router();
$query = $this->make_query( array(
'post_type' => 'product',
'meta_query' => array(
array( 'key' => '_price', 'value' => '50', 'compare' => '>=' ),
),
) );
$router->pre_get_posts( $query );
// Original meta_query stripped of registered keys.
$remaining = $query->get( 'meta_query' );
$this->assertEmpty(
$remaining,
'aeav_only: registered keys removed from meta_query.'
);
// Routed clauses captured under wpdo_post_clauses query var.
$routed = $query->get( 'wpdo_post_clauses' );
$this->assertIsArray( $routed );
$this->assertNotEmpty( $routed );
}
public function test_keeps_unmanaged_keys_in_meta_query(): void {
$this->set_post_mode( 'aeav_only' );
$router = new WPDO_Post_Query_Router();
$query = $this->make_query( array(
'post_type' => 'product',
'meta_query' => array(
array( 'key' => '_price', 'value' => '50', 'compare' => '>=' ),
array( 'key' => 'unmanaged_attr', 'value' => 'x' ),
),
) );
$router->pre_get_posts( $query );
$remaining = $query->get( 'meta_query' );
$this->assertCount( 1, $remaining );
// Original index preserved (k=1 since k=0 was the routed _price clause).
$first_clause = reset( $remaining );
$this->assertSame(
'unmanaged_attr',
$first_clause['key'],
'Unmanaged key remains in meta_query (Hook Bus pass-through).'
);
}
public function test_skips_admin_requests(): void {
$this->set_post_mode( 'aeav_only' );
$prev_admin = $GLOBALS['_wp_is_admin'] ?? false;
$GLOBALS['_wp_is_admin'] = true;
$router = new WPDO_Post_Query_Router();
$query = $this->make_query( array(
'post_type' => 'product',
'meta_query' => array(
array( 'key' => '_price', 'value' => '50', 'compare' => '>=' ),
),
) );
$original = $query->get( 'meta_query' );
$router->pre_get_posts( $query );
$this->assertSame(
$original,
$query->get( 'meta_query' ),
'is_admin requests should not be rewritten.'
);
$GLOBALS['_wp_is_admin'] = $prev_admin;
}
// ── posts_join / posts_where (SQL emission) ──────────────────────────────
public function test_posts_join_emits_left_join_for_each_routed_post_type(): void {
$this->set_post_mode( 'aeav_only' );
$router = new WPDO_Post_Query_Router();
$query = $this->make_query( array(
'post_type' => 'product',
'meta_query' => array(
array( 'key' => '_price', 'value' => '50' ),
),
'wpdo_post_clauses' => array(),
) );
$router->pre_get_posts( $query );
$join = $router->posts_join( '', $query );
$this->assertStringContainsString( 'LEFT JOIN', $join );
$this->assertStringContainsString( 'wpdo_post_wc_product', $join );
}
public function test_posts_where_appends_condition_for_routed_clause(): void {
$this->set_post_mode( 'aeav_only' );
$router = new WPDO_Post_Query_Router();
$query = $this->make_query( array(
'post_type' => 'product',
'meta_query' => array(
array( 'key' => '_price', 'value' => '99', 'compare' => '=' ),
),
) );
$router->pre_get_posts( $query );
$where = $router->posts_where( '', $query );
$this->assertStringContainsString( '`_price`', $where );
$this->assertStringContainsString( "'99'", $where );
}
public function test_pass_through_when_no_meta_query(): void {
$this->set_post_mode( 'aeav_only' );
$router = new WPDO_Post_Query_Router();
$query = $this->make_query( array( 'post_type' => 'product' ) );
$router->pre_get_posts( $query );
$this->assertSame( '', $query->get( 'wpdo_post_clauses' ) );
}
}