fix(2meet-data-optimizer-hivepress-addon): let transient timeouts outlive their values; register site attributes once themes load
- review F5: a timeout entry expired before its value (a day vs a week), and HivePress reads a missing timeout as "never expires", serving the stale value for up to six more days. The timeout now expires a minute after the later of MAX_CACHE_TTL and its own time, so HivePress sees it expire first - review F7: site attributes accept only types with a plain index (json and binary would fail the CREATE TABLE) - review F8: the hp_listing_attrs group is registered on the run after after_setup_theme (init:1), so a filter added in a theme counts and the group has one definition per request; only keys of other groups are skipped - Verify: TTL test, attribute group tests, unit 148, integration 53, phpcs - PR: PR-115 (2.3 acceptance correctness review)
This commit is contained in:
@@ -24,6 +24,12 @@ if ( ! file_exists( $tmdo_core_bootstrap ) ) {
|
||||
}
|
||||
require_once $tmdo_core_bootstrap;
|
||||
|
||||
if ( ! function_exists( 'did_action' ) ) {
|
||||
function did_action( string $hook ): int {
|
||||
return (int) ( $GLOBALS['_wp_did_action'][ $hook ] ?? 0 );
|
||||
}
|
||||
}
|
||||
|
||||
define( 'TMDO_HIVEPRESS_PATH', dirname( __DIR__ ) . '/' );
|
||||
define( 'TMDO_HIVEPRESS_URL', 'http://localhost/wp-content/plugins/2meet-data-optimizer-hivepress-addon/' );
|
||||
define( 'TMDO_HIVEPRESS_FILE', dirname( __DIR__ ) . '/2meet-data-optimizer-hivepress-addon.php' );
|
||||
|
||||
@@ -214,9 +214,10 @@ class HivepressTransientFilterTest extends TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Entries expire in the object cache too (2.3 PR-099): the timeout at the
|
||||
* time it records, the value (written first, before its timeout is known)
|
||||
* after at most a week. Orphans of deleted posts no longer pile up.
|
||||
* Entries expire in the object cache too (2.3 PR-099): the value (written
|
||||
* first, before its timeout is known) after a week, the timeout after the
|
||||
* later of that and its own time, plus a minute. Orphans of deleted posts
|
||||
* no longer pile up.
|
||||
*/
|
||||
public function test_with_an_object_cache_entries_get_a_ttl(): void {
|
||||
$GLOBALS['_wp_using_ext_object_cache'] = true;
|
||||
@@ -229,8 +230,12 @@ class HivepressTransientFilterTest extends TestCase {
|
||||
|
||||
$ttl = $GLOBALS['_wp_cache_ttl'][ WPDO_Hivepress_Transient_Filter::CACHE_GROUP ];
|
||||
$this->assertSame( WPDO_Hivepress_Transient_Filter::MAX_CACHE_TTL, $ttl[ '_transient_' . $translated ] );
|
||||
$this->assertEqualsWithDelta( 3600, $ttl[ '_transient_timeout_' . $translated ], 2 );
|
||||
$this->assertSame( 1, $ttl[ '_transient_timeout_' . WPDO_Hivepress_Transient_Filter::translate_key( 101, $key ) ], 'already expired' );
|
||||
// A timeout must outlive its value: HivePress takes a missing timeout for
|
||||
// "never expires" and would serve the stale value (review F5).
|
||||
$this->assertSame( WPDO_Hivepress_Transient_Filter::MAX_CACHE_TTL + 60, $ttl[ '_transient_timeout_' . $translated ] );
|
||||
$this->assertSame( WPDO_Hivepress_Transient_Filter::MAX_CACHE_TTL + 60, $ttl[ '_transient_timeout_' . WPDO_Hivepress_Transient_Filter::translate_key( 101, $key ) ], 'already expired' );
|
||||
WPDO_Hivepress_Transient_Filter::on_update( null, 102, '_transient_timeout_hp_models/cat/v1', (string) ( time() + 2 * WPDO_Hivepress_Transient_Filter::MAX_CACHE_TTL ), '' );
|
||||
$this->assertEqualsWithDelta( 2 * WPDO_Hivepress_Transient_Filter::MAX_CACHE_TTL + 60, $GLOBALS['_wp_cache_ttl'][ WPDO_Hivepress_Transient_Filter::CACHE_GROUP ][ '_transient_timeout_' . WPDO_Hivepress_Transient_Filter::translate_key( 102, $key ) ], 2 );
|
||||
}
|
||||
|
||||
public function test_with_an_object_cache_a_value_left_in_wp_options_is_not_read(): void {
|
||||
|
||||
@@ -88,8 +88,10 @@ class HivePressEntityGroupsTest extends TestCase {
|
||||
'hp_price' => 'decimal', // Already in hp_listing_core.
|
||||
'warranty' => 'integer', // Not a HivePress key.
|
||||
'hp_color' => 'colour', // Unknown type.
|
||||
'hp_features' => 'json', // No plain index on LONGTEXT.
|
||||
);
|
||||
add_filter( 'tmdo_hp_listing_attribute_fields', $fields );
|
||||
$GLOBALS['_wp_did_action']['after_setup_theme'] = 1;
|
||||
try {
|
||||
TMDO_Entity_Registry::init();
|
||||
TMDO_Entity_Registry::register_adapter( 'post', $this->createMock( TMDO_Entity_Adapter_Interface::class ) );
|
||||
@@ -97,6 +99,7 @@ class HivePressEntityGroupsTest extends TestCase {
|
||||
TMDO_HivePress_Entity_Groups::register_entity_fields();
|
||||
} finally {
|
||||
$GLOBALS['_wp_filter_callbacks']['tmdo_hp_listing_attribute_fields'] = array();
|
||||
unset( $GLOBALS['_wp_did_action'] );
|
||||
}
|
||||
|
||||
$this->assertSame( array( 'hp_warranty' ), TMDO_Entity_Registry::get_group_keys( 'post', 'hp_listing_attrs' ) );
|
||||
@@ -106,6 +109,31 @@ class HivePressEntityGroupsTest extends TestCase {
|
||||
$this->test_definitions_match_persisted_schema_hashes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registration runs twice (plugins_loaded, then init:1): the group is
|
||||
* registered on the run after themes load, so a theme's filter counts and
|
||||
* a filter that changed between runs cannot collide (review F8).
|
||||
*/
|
||||
public function test_site_listing_attributes_are_registered_once_themes_are_loaded(): void {
|
||||
add_filter( 'tmdo_hp_listing_attribute_fields', static fn() => array( 'hp_warranty' => 'integer' ) );
|
||||
try {
|
||||
TMDO_Entity_Registry::init();
|
||||
TMDO_Entity_Registry::register_adapter( 'post', $this->createMock( TMDO_Entity_Adapter_Interface::class ) );
|
||||
TMDO_Entity_Registry::register_adapter( 'user', $this->createMock( TMDO_Entity_Adapter_Interface::class ) );
|
||||
TMDO_HivePress_Entity_Groups::register_entity_fields();
|
||||
$this->assertSame( array(), TMDO_Entity_Registry::get_group_keys( 'post', 'hp_listing_attrs' ), 'plugins_loaded run: not yet' );
|
||||
|
||||
$GLOBALS['_wp_did_action']['after_setup_theme'] = 1;
|
||||
TMDO_HivePress_Entity_Groups::register_entity_fields();
|
||||
} finally {
|
||||
$GLOBALS['_wp_filter_callbacks']['tmdo_hp_listing_attribute_fields'] = array();
|
||||
unset( $GLOBALS['_wp_did_action'] );
|
||||
}
|
||||
|
||||
$this->assertSame( array( 'hp_warranty' ), TMDO_Entity_Registry::get_group_keys( 'post', 'hp_listing_attrs' ) );
|
||||
$this->assertSame( array(), TMDO_Entity_Registry::get_collisions() );
|
||||
}
|
||||
|
||||
public function test_shared_keys_keep_their_current_owner(): void {
|
||||
foreach ( self::SHARED_KEY_OWNERS as $key => $group ) {
|
||||
$this->assertSame( $group, TMDO_Entity_Registry::get_field( 'post', $key )['group'], $key );
|
||||
|
||||
Reference in New Issue
Block a user