b84252d787
- 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
97 lines
3.9 KiB
PHP
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' );
|
|
}
|
|
);
|