Files
2meet-data-optimizer/tests/live/suites/shadow_write.php
T
wpdev b84252d787 fix(2meet-data-optimizer): serve native meta in shadow_read and compare flat values
- In shadow_read, TMDO_Hook_Bus::intercept_get() returned the flat value.
  update_metadata() reads the old value through that filter after the Hook
  Bus has upserted the new one, so WP saw old === new and never wrote native
  meta: every update in shadow_read was lost on demotion (dev36 2026-09-26).
  shadow_read now returns $check (native) and compares flat on a sample of
  reads (filter tmdo_shadow_compare_sample_rate, default 0.1). aeav_only is
  unchanged; the post query router still routes in shadow_read.
- Live suite shadow_write: xfail markers removed, HivePress listing case
  added (new int key hp_rating_count); fixtures gain post() and a
  post_type-scoped field()/flat().
- Verify: live shadow_write + serialized 8/8 PASS (old code: 4 FAIL);
  unit 685 OK, integration 484 OK, phpcs (phpcs.xml) 0, stan OK
- PR: PR-056
2026-09-26 18:56:45 +08:00

97 lines
3.9 KiB
PHP

<?php
/**
* Suite: writes made in shadow_read must reach native meta.
*
* Bug (dev36, 2026-09-26): in shadow_read, update_metadata() fetches the old
* value through get_metadata_raw(); the Hook Bus has already upserted the new
* value and serves it from the flat table, so WP sees old === new and returns
* false without writing native meta. Demoting afterwards exposes stale data.
*
* @package WP_Data_Optimizer
*/
declare(strict_types=1);
TMDO_Live::test(
'dual_write: user first_name update reaches native and flat (control)',
static function () {
TMDO_Live_Fixtures::field( 'user', 'first_name' );
TMDO_Live_Fixtures::use_modes( array( 'user' => 'dual_write' ) );
$uid = TMDO_Live_Fixtures::user();
update_user_meta( $uid, 'first_name', 'Before' );
$ret = update_user_meta( $uid, 'first_name', 'After' );
tmdo_live_assert_true( false !== $ret, 'update_user_meta returned false' );
tmdo_live_assert_same( array( 'After' ), TMDO_Live_Fixtures::native( 'user', $uid, 'first_name' ), 'native first_name' );
tmdo_live_assert_same( 'After', TMDO_Live_Fixtures::flat( 'user', $uid, 'first_name' ), 'flat first_name' );
}
);
TMDO_Live::test(
'shadow_read: user first_name update reaches native',
static function () {
TMDO_Live_Fixtures::field( 'user', 'first_name' );
TMDO_Live_Fixtures::use_modes( array( 'user' => 'dual_write' ) );
$uid = TMDO_Live_Fixtures::user();
update_user_meta( $uid, 'first_name', 'Before' );
TMDO_Live_Fixtures::use_modes( array( 'user' => 'shadow_read' ) );
$ret = update_user_meta( $uid, 'first_name', 'After' );
tmdo_live_assert_true( false !== $ret, 'update_user_meta returned false' );
tmdo_live_assert_same( array( 'After' ), TMDO_Live_Fixtures::native( 'user', $uid, 'first_name' ), 'native first_name' );
}
);
TMDO_Live::test(
'shadow_read → dual_write: value written in shadow_read survives demotion',
static function () {
TMDO_Live_Fixtures::field( 'user', 'last_name' );
TMDO_Live_Fixtures::use_modes( array( 'user' => 'dual_write' ) );
$uid = TMDO_Live_Fixtures::user();
update_user_meta( $uid, 'last_name', 'Before' );
TMDO_Live_Fixtures::use_modes( array( 'user' => 'shadow_read' ) );
update_user_meta( $uid, 'last_name', 'After' );
TMDO_Live_Fixtures::use_modes( array( 'user' => 'dual_write' ) );
wp_cache_delete( $uid, 'user_meta' );
tmdo_live_assert_same( 'After', get_user_meta( $uid, 'last_name', true ), 'last_name after demotion' );
}
);
TMDO_Live::test(
'shadow_read: HivePress term hp_icon update reaches native',
static function () {
TMDO_Live_Fixtures::field( 'term', 'hp_icon' );
TMDO_Live_Fixtures::use_modes( array( 'term' => 'dual_write' ) );
$tid = TMDO_Live_Fixtures::term( 'hp_listing_category' );
update_term_meta( $tid, 'hp_icon', 'star' );
TMDO_Live_Fixtures::use_modes( array( 'term' => 'shadow_read' ) );
$ret = update_term_meta( $tid, 'hp_icon', 'heart' );
tmdo_live_assert_true( false !== $ret, 'update_term_meta returned false' );
tmdo_live_assert_same( array( 'heart' ), TMDO_Live_Fixtures::native( 'term', $tid, 'hp_icon' ), 'native hp_icon' );
}
);
TMDO_Live::test(
'shadow_read: HivePress listing hp_rating_count (new int key) reaches native',
static function () {
TMDO_Live_Fixtures::field( 'post', 'hp_rating_count', 'hp_listing' );
TMDO_Live_Fixtures::use_modes( array( 'post' => 'dual_write' ) );
$lid = TMDO_Live_Fixtures::post( 'hp_listing' );
TMDO_Live_Fixtures::use_modes( array( 'post' => 'shadow_read' ) );
// HivePress writes the recomputed count as an int; the flat read cast it
// to the same int, so the old code skipped the native write.
$ret = update_post_meta( $lid, 'hp_rating_count', 1 );
tmdo_live_assert_true( false !== $ret, 'update_post_meta returned false' );
tmdo_live_assert_same( array( '1' ), TMDO_Live_Fixtures::native( 'post', $lid, 'hp_rating_count' ), 'native hp_rating_count' );
tmdo_live_assert_same( '1', TMDO_Live_Fixtures::flat( 'post', $lid, 'hp_rating_count', 'hp_listing' ), 'flat hp_rating_count' );
}
);