Files
2meet-data-optimizer/tests/live/tools/seed.php
T
wpdev f72a315986 test(2meet-data-optimizer): add live test runner and failing shadow_read write suite
- 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
2026-09-26 18:21:31 +08:00

159 lines
7.0 KiB
PHP

<?php
/**
* dev36 integration seeder — goes through the real APIs (HivePress models, WC CRUD,
* wp_insert_user / update_*_meta) so every write passes the Hook Bus exactly like prod.
*
* Usage: wp eval-file seed.php <kind> <count> [tag]
* kind: vendors | listings | requests | reviews | products | orders | terms
*/
use HivePress\Models;
add_filter( 'pre_wp_mail', '__return_true' );
// WC Tracks pings pixel.wp.com ~3x per product save (~180 ms each); irrelevant to the test.
add_filter( 'pre_http_request', function ( $r, $a, $url ) { return false !== strpos( $url, 'pixel.wp.com' ) ? array( 'headers' => array(), 'body' => '', 'response' => array( 'code' => 200, 'message' => 'OK' ), 'cookies' => array() ) : $r; }, 1, 3 );
wp_defer_term_counting( true );
wp_defer_comment_counting( true );
$kind = $args[0] ?? '';
$count = (int) ( $args[1] ?? 0 );
$tag = $args[2] ?? 'b1';
mt_srand( crc32( $kind . $tag ) );
$cities = array( 'Taipei', 'Taichung', 'Kaohsiung', 'Tainan', 'Hsinchu', 'Keelung' );
function s36_pick_ids( $post_type, $limit = 5000 ) {
global $wpdb;
return array_map( 'intval', $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_type=%s AND post_status='publish' ORDER BY RAND() LIMIT %d", $post_type, $limit ) ) );
}
$t0 = microtime( true );
$q0 = get_num_queries();
$ok = 0;
switch ( $kind ) {
case 'vendors':
for ( $i = 0; $i < $count; $i++ ) {
$login = "s36v_{$tag}_{$i}";
$uid = wp_insert_user( array( 'user_login' => $login, 'user_email' => "$login@example.test", 'user_pass' => wp_generate_password(), 'role' => 'contributor', 'first_name' => "F$i", 'last_name' => "L$i", 'description' => "Vendor $i bio" ) );
if ( is_wp_error( $uid ) ) { continue; }
update_user_meta( $uid, 'billing_city', $cities[ $i % 6 ] );
update_user_meta( $uid, 'billing_phone', '09' . mt_rand( 10000000, 99999999 ) );
update_user_meta( $uid, 'facebook', "https://facebook.com/$login" );
update_user_meta( $uid, 'login_count', mt_rand( 1, 300 ) );
$v = ( new Models\Vendor() )->fill( array( 'name' => "Vendor $tag $i", 'description' => 'Seeded vendor', 'status' => 'publish', 'user' => $uid, 'verified' => (bool) mt_rand( 0, 1 ) ) );
if ( $v->save() ) {
update_post_meta( $v->get_id(), 'hp_hourly_rate', mt_rand( 10, 300 ) );
update_post_meta( $v->get_id(), 'hp_rating', mt_rand( 10, 50 ) / 10 );
$ok++;
}
}
break;
case 'listings':
global $wpdb;
$vendors = $wpdb->get_results( "SELECT ID, post_author FROM {$wpdb->posts} WHERE post_type='hp_vendor' AND post_status='publish'" );
$cats = get_terms( array( 'taxonomy' => 'hp_listing_category', 'hide_empty' => false, 'fields' => 'ids' ) );
for ( $i = 0; $i < $count; $i++ ) {
$v = $vendors[ array_rand( $vendors ) ];
$l = ( new Models\Listing() )->fill( array(
'title' => "Listing $tag $i " . $cities[ $i % 6 ],
'description' => str_repeat( 'Seeded listing body. ', 8 ),
'status' => ( mt_rand( 1, 10 ) <= 9 ) ? 'publish' : 'draft',
'user' => (int) $v->post_author,
'vendor' => (int) $v->ID,
'featured' => mt_rand( 1, 20 ) === 1,
'verified' => mt_rand( 1, 3 ) === 1,
'categories' => $cats ? array( $cats[ array_rand( $cats ) ] ) : array(),
) );
if ( $l->save() ) {
$id = $l->get_id();
update_post_meta( $id, 'hp_price', mt_rand( 100, 50000 ) );
update_post_meta( $id, 'hp_hourly_rate', mt_rand( 10, 300 ) );
update_post_meta( $id, 'hp_warranty', mt_rand( 0, 24 ) );
$ok++;
}
}
break;
case 'requests':
$users = get_users( array( 'fields' => 'ID', 'number' => 3000, 'orderby' => 'rand' ) );
for ( $i = 0; $i < $count; $i++ ) {
$r = ( new Models\Request() )->fill( array( 'title' => "Request $tag $i", 'description' => 'Need help', 'status' => 'publish', 'user' => (int) $users[ array_rand( $users ) ] ) );
if ( $r->save() ) {
update_post_meta( $r->get_id(), 'hp_budget', mt_rand( 500, 90000 ) );
update_post_meta( $r->get_id(), 'hp_due_date', gmdate( 'Y-m-d', time() + mt_rand( 1, 90 ) * DAY_IN_SECONDS ) );
$ok++;
}
}
break;
case 'reviews':
$listings = s36_pick_ids( 'hp_listing' );
$users = get_users( array( 'fields' => array( 'ID', 'display_name', 'user_email' ), 'number' => 3000, 'orderby' => 'rand' ) );
for ( $i = 0; $i < $count; $i++ ) {
$u = $users[ array_rand( $users ) ];
$rv = ( new Models\Review() )->fill( array( 'text' => "Review $tag $i", 'rating' => mt_rand( 1, 5 ), 'approved' => 1, 'author' => (int) $u->ID, 'author__display_name' => $u->display_name, 'author__email' => $u->user_email, 'listing' => $listings[ array_rand( $listings ) ] ) );
if ( $rv->save() ) { $ok++; }
}
break;
case 'terms':
for ( $i = 0; $i < $count; $i++ ) {
$t = wp_insert_term( "Cat $tag $i", 'hp_listing_category' );
if ( ! is_wp_error( $t ) ) {
update_term_meta( $t['term_id'], 'hp_sort_order', $i );
update_term_meta( $t['term_id'], 'hp_icon', 'star' );
$ok++;
}
}
break;
case 'products':
$pcats = get_terms( array( 'taxonomy' => 'product_cat', 'hide_empty' => false, 'fields' => 'ids' ) );
for ( $i = 0; $i < $count; $i++ ) {
$p = new WC_Product_Simple();
$p->set_name( "Product $tag $i" );
$p->set_status( 'publish' );
$reg = mt_rand( 100, 20000 );
$p->set_regular_price( (string) $reg );
if ( mt_rand( 1, 4 ) === 1 ) { $p->set_sale_price( (string) (int) ( $reg * 0.8 ) ); }
$p->set_sku( "S36-$tag-$i" );
$p->set_manage_stock( true );
$p->set_stock_quantity( mt_rand( 0, 500 ) );
if ( $pcats ) { $p->set_category_ids( array( $pcats[ array_rand( $pcats ) ] ) ); }
if ( $p->save() ) { $ok++; }
}
break;
case 'orders':
$products = wc_get_products( array( 'limit' => 2000, 'status' => 'publish', 'orderby' => 'rand', 'return' => 'ids' ) );
$users = get_users( array( 'fields' => 'ID', 'number' => 3000, 'orderby' => 'rand' ) );
$statuses = array( 'completed', 'completed', 'processing', 'on-hold', 'cancelled', 'refunded' );
for ( $i = 0; $i < $count; $i++ ) {
$o = wc_create_order( array( 'customer_id' => (int) $users[ array_rand( $users ) ] ) );
if ( is_wp_error( $o ) ) { continue; }
$n = mt_rand( 1, 3 );
for ( $j = 0; $j < $n; $j++ ) { $o->add_product( wc_get_product( $products[ array_rand( $products ) ] ), mt_rand( 1, 3 ) ); }
$o->set_billing_city( $cities[ $i % 6 ] );
$o->set_billing_email( "buyer$i@example.test" );
$o->calculate_totals( false );
$o->set_status( $statuses[ array_rand( $statuses ) ] );
$o->save();
$ok++;
}
break;
default:
WP_CLI::error( "unknown kind $kind" );
}
wp_defer_term_counting( false );
wp_defer_comment_counting( false );
$el = microtime( true ) - $t0;
$q = get_num_queries() - $q0;
WP_CLI::log( sprintf( 'SEED %s x%d ok=%d %.1fs %.2f ms/item %.1f queries/item mode(post=%s,user=%s,term=%s,comment=%s)',
$kind, $count, $ok, $el, $ok ? $el * 1000 / $ok : 0, $ok ? $q / $ok : 0,
...( class_exists( 'TMDO_Mode_Manager' ) ? array( TMDO_Mode_Manager::get( 'post' ), TMDO_Mode_Manager::get( 'user' ), TMDO_Mode_Manager::get( 'term' ), TMDO_Mode_Manager::get( 'comment' ) ) : array( 'NO-TMDO', '-', '-', '-' ) ) ) );