f72a315986
- Add tests/live: a `wp eval-file` runner (PASS/FAIL/XFAIL/XPASS/SKIP) with fixtures that override entity modes in process (pre_option) and read native / flat values with plain SQL, so WP core meta flows run for real - shadow_write suite reproduces the dev36 finding: in shadow_read, update_*_meta returns false and native meta is never written (3 XFAIL marked for PR-056); the dual_write control passes - Move the dev36 integration harness into tests/live/tools; outputs go to cwd / $TMDO_LIVE_OUT, site URL and path are env-configurable - Verify: wp --path=<dev36> eval-file tests/live/run.php shadow_write → 1 passed, 3 xfail; unit 658 OK, integration 480 OK, phpcs (phpcs.xml) 0, stan OK - PR: PR-052
66 lines
5.1 KiB
PHP
66 lines
5.1 KiB
PHP
<?php
|
|
/**
|
|
* Query correctness + latency harness. Runs identical WP_Query shapes and dumps
|
|
* ids / found_posts / timings to JSON so two runs (native vs routed mode) can be diffed.
|
|
* Usage: wp eval-file qbench.php <label> [iterations]
|
|
*/
|
|
global $wpdb;
|
|
$label = $args[0] ?? 'run';
|
|
$iters = (int) ( $args[1] ?? 5 );
|
|
$out = getcwd() . "/qbench_{$label}.json";
|
|
|
|
// Deterministic parameters derived from data (same in every run).
|
|
$vendor_ids = array_map( 'intval', $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE post_type='hp_vendor' AND post_status='publish' ORDER BY ID LIMIT 3" ) );
|
|
|
|
$L = array( 'post_type' => 'hp_listing', 'post_status' => 'publish', 'posts_per_page' => 20 );
|
|
$cases = array(
|
|
'Q01 price BETWEEN (NUMERIC)' => $L + array( 'meta_query' => array( array( 'key' => 'hp_price', 'value' => array( 10000, 20000 ), 'compare' => 'BETWEEN', 'type' => 'NUMERIC' ) ) ),
|
|
'Q02 price >= AND verified=1' => $L + array( 'meta_query' => array( 'relation' => 'AND', array( 'key' => 'hp_price', 'value' => 25000, 'compare' => '>=', 'type' => 'NUMERIC' ), array( 'key' => 'hp_verified', 'value' => '1' ) ) ),
|
|
'Q03 rating >= 4.5 (DECIMAL)' => $L + array( 'meta_query' => array( array( 'key' => 'hp_rating', 'value' => '4.5', 'compare' => '>=', 'type' => 'DECIMAL(10,2)' ) ) ),
|
|
'Q04 featured=1 OR verified=1' => $L + array( 'meta_query' => array( 'relation' => 'OR', array( 'key' => 'hp_featured', 'value' => '1' ), array( 'key' => 'hp_verified', 'value' => '1' ) ) ),
|
|
'Q05 rate>=100 AND _thumbnail EXISTS'=> $L + array( 'meta_query' => array( array( 'key' => 'hp_hourly_rate', 'value' => 100, 'compare' => '>=', 'type' => 'NUMERIC' ), array( 'key' => '_thumbnail_id', 'compare' => 'EXISTS' ) ) ),
|
|
'Q06 product _sku LIKE' => array( 'post_type' => 'product', 'post_status' => 'publish', 'posts_per_page' => 20, 'meta_query' => array( array( 'key' => '_sku', 'value' => 'S36-B1-1', 'compare' => 'LIKE' ) ) ),
|
|
'Q07 orderby meta_value_num price' => $L + array( 'meta_key' => 'hp_price', 'orderby' => 'meta_value_num', 'order' => 'DESC' ),
|
|
'Q08 multi post_type + hp_budget' => array( 'post_type' => array( 'hp_listing', 'hp_request' ), 'post_status' => 'publish', 'posts_per_page' => 20, 'meta_query' => array( array( 'key' => 'hp_budget', 'value' => 80000, 'compare' => '>=', 'type' => 'NUMERIC' ) ) ),
|
|
'Q09 featured NOT EXISTS' => $L + array( 'meta_query' => array( array( 'key' => 'hp_featured', 'compare' => 'NOT EXISTS' ) ) ),
|
|
'Q10 rating_count != 1' => $L + array( 'meta_query' => array( array( 'key' => 'hp_rating_count', 'value' => '1', 'compare' => '!=' ) ) ),
|
|
'Q11 product _price BETWEEN+instock' => array( 'post_type' => 'product', 'post_status' => 'publish', 'posts_per_page' => 20, 'meta_query' => array( array( 'key' => '_price', 'value' => array( 1000, 5000 ), 'compare' => 'BETWEEN', 'type' => 'NUMERIC' ), array( 'key' => '_stock_status', 'value' => 'instock' ) ) ),
|
|
'Q12 request budget > (NUMERIC)' => array( 'post_type' => 'hp_request', 'post_status' => 'publish', 'posts_per_page' => 20, 'meta_query' => array( array( 'key' => 'hp_budget', 'value' => 50000, 'compare' => '>', 'type' => 'NUMERIC' ) ) ),
|
|
'Q13 rating_count IN (1,2)' => $L + array( 'meta_query' => array( array( 'key' => 'hp_rating_count', 'value' => array( 1, 2 ), 'compare' => 'IN' ) ) ),
|
|
'Q16 price<1000 OR warranty=0 (mix)' => $L + array( 'meta_query' => array( 'relation' => 'OR', array( 'key' => 'hp_price', 'value' => 1000, 'compare' => '<', 'type' => 'NUMERIC' ), array( 'key' => 'hp_warranty', 'value' => '0' ) ) ),
|
|
'Q14 price > (CHAR, no type)' => $L + array( 'meta_query' => array( array( 'key' => 'hp_price', 'value' => '9000', 'compare' => '>' ) ) ),
|
|
'Q15 hourly_rate < 50 orderby price' => $L + array( 'meta_query' => array( 'rate' => array( 'key' => 'hp_hourly_rate', 'value' => 50, 'compare' => '<', 'type' => 'NUMERIC' ), 'price' => array( 'key' => 'hp_price', 'type' => 'NUMERIC', 'compare' => 'EXISTS' ) ), 'orderby' => 'price', 'order' => 'ASC' ),
|
|
);
|
|
|
|
$res = array();
|
|
foreach ( $cases as $name => $qa ) {
|
|
$times = array();
|
|
$ids = null;
|
|
$found = null;
|
|
$err = '';
|
|
$sql = '';
|
|
for ( $i = 0; $i < $iters; $i++ ) {
|
|
wp_cache_flush_group( 'tmdo_found_rows' );
|
|
$wpdb->last_error = '';
|
|
$t = microtime( true );
|
|
$q = new WP_Query( $qa + array( 'fields' => 'ids', 'cache_results' => false, 'suppress_filters' => false ) );
|
|
$times[] = ( microtime( true ) - $t ) * 1000;
|
|
$ids = array_map( 'intval', $q->posts );
|
|
$found = (int) $q->found_posts;
|
|
$sql = $q->request;
|
|
if ( $wpdb->last_error ) { $err = $wpdb->last_error; }
|
|
}
|
|
sort( $times );
|
|
$res[ $name ] = array(
|
|
'found' => $found,
|
|
'ids' => $ids,
|
|
'p50' => round( $times[ (int) floor( count( $times ) / 2 ) ], 2 ),
|
|
'max' => round( max( $times ), 2 ),
|
|
'err' => $err,
|
|
'sql' => preg_replace( '/\s+/', ' ', $sql ),
|
|
);
|
|
printf( "%-36s found=%-6d p50=%8.2fms %s\n", $name, $found, $res[ $name ]['p50'], $err ? "ERR: $err" : '' );
|
|
}
|
|
file_put_contents( $out, wp_json_encode( array( 'mode' => TMDO_Mode_Manager::get( 'post' ), 'res' => $res ), JSON_PRETTY_PRINT ) );
|
|
echo "saved $out (post mode=" . TMDO_Mode_Manager::get( 'post' ) . ")\n";
|