f06a80eae5
- hp_listing_core declares indexes on hp_hourly_rate and hp_rating_count; core adds them in place (WP-CLI / WP-Cron), the pinned schema hash is unchanged - Verify: unit 145, integration 52, phpcs; dev36 902k listings (SHOW INDEX, EXPLAIN) - PR: PR-090
162 lines
6.5 KiB
PHP
162 lines
6.5 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
/**
|
|
* The AddOn owns the HivePress entity groups core used to register.
|
|
*
|
|
* Their definitions are persisted (wpdo_registry_meta schema hash) and the
|
|
* flat tables on live sites were built from them, so they are pinned to the
|
|
* persisted hashes: any drift would ALTER flat tables that may hold
|
|
* aeav_only data. (Values recorded on dev20, 2026-09-25.)
|
|
*/
|
|
class HivePressEntityGroupsTest extends TestCase {
|
|
|
|
private const PERSISTED_HASHES = array(
|
|
'post/hp_listing_core' => 'fb5ab760',
|
|
'post/hp_request_core' => '27d6f4f5',
|
|
'post/hp_vendor_core' => '5366e5c8',
|
|
'user/hp_user' => '61ac526f',
|
|
);
|
|
|
|
/**
|
|
* Lookups that do not pass a post type (or run with scoped routing off,
|
|
* until a site's rows are reconciled) keep the legacy owner of keys shared
|
|
* by several post groups: the LAST group registered. Pinned so the
|
|
* registration order cannot change silently.
|
|
*/
|
|
private const SHARED_KEY_OWNERS = array(
|
|
'hp_status' => 'hp_request_core',
|
|
'hp_expired_time' => 'hp_request_core',
|
|
'hp_view_count' => 'hp_request_core',
|
|
'hp_verified' => 'hp_vendor_core',
|
|
'hp_rating' => 'hp_vendor_core',
|
|
'hp_rating_count' => 'hp_vendor_core',
|
|
'hp_hourly_rate' => 'hp_vendor_core',
|
|
'hp_user' => 'hp_vendor_core',
|
|
);
|
|
|
|
protected function setUp(): void {
|
|
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();
|
|
}
|
|
|
|
protected function tearDown(): void {
|
|
unset( $GLOBALS['_wp_options'][ TMDO_Entity_Registry::SCOPED_ROUTING_OPTION ] );
|
|
unset( $GLOBALS['_wp_filter_callbacks']['tmdo_rest_default_post_type'] );
|
|
}
|
|
|
|
public function test_definitions_match_persisted_schema_hashes(): void {
|
|
foreach ( self::PERSISTED_HASHES as $id => $hash ) {
|
|
list( $type, $group ) = explode( '/', $id );
|
|
$fields = TMDO_Entity_Registry::get_group_fields( $type, $group );
|
|
$this->assertNotEmpty( $fields, "{$id} not registered" );
|
|
$this->assertSame( $hash, substr( TMDO_Schema_Manager::calculate_schema_hash( $fields ), 0, 8 ), "{$id} drifted from the persisted definition" );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* HivePress filters and sorts listings by these; they are declared as
|
|
* group indexes (added in place by core) rather than `searchable`, which
|
|
* would change the pinned hash and rebuild the table.
|
|
*/
|
|
public function test_listing_columns_filtered_and_sorted_on_are_indexed(): void {
|
|
$this->assertSame(
|
|
array(
|
|
'hourly_rate' => array( 'hp_hourly_rate' ),
|
|
'rating_count' => array( 'hp_rating_count' ),
|
|
),
|
|
TMDO_Entity_Registry::get_group_indexes( 'post', 'hp_listing_core' )
|
|
);
|
|
}
|
|
|
|
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 );
|
|
}
|
|
}
|
|
|
|
public function test_shared_keys_follow_the_post_type_when_scoped_routing_is_on(): void {
|
|
$GLOBALS['_wp_options'][ TMDO_Entity_Registry::SCOPED_ROUTING_OPTION ] = '1';
|
|
|
|
foreach ( array( 'hp_listing' => 'hp_listing_core', 'hp_request' => 'hp_request_core', 'hp_vendor' => 'hp_vendor_core' ) as $post_type => $group ) {
|
|
foreach ( TMDO_Entity_Registry::get_group_keys( 'post', $group ) as $key ) {
|
|
$this->assertSame( $group, TMDO_Entity_Registry::get_field( 'post', $key, $post_type )['group'], "{$post_type}:{$key}" );
|
|
}
|
|
}
|
|
$this->assertNull( TMDO_Entity_Registry::get_field( 'post', 'hp_rating', 'post' ), 'HivePress keys stay native on other post types' );
|
|
}
|
|
|
|
/**
|
|
* Fields only the Hot zone used to cover (ADR-003), as their own groups.
|
|
*/
|
|
private const HOT_ONLY_GROUPS = array(
|
|
'hp_draft_flags' => array( array( 'hp_listing', 'hp_request' ), array( 'hp_drafted' ) ),
|
|
'hp_booking_core' => array( array( 'hp_booking' ), array( 'hp_start_time', 'hp_end_time', 'hp_quantity' ) ),
|
|
'hp_membership_plan_core' => array( array( 'hp_membership_plan' ), array( 'hp_expire_period', 'hp_primary' ) ),
|
|
'hp_membership_core' => array( array( 'hp_membership' ), array( 'hp_expired_time' ) ),
|
|
);
|
|
|
|
public function test_hot_only_fields_have_entity_groups_scoped_to_their_post_types(): void {
|
|
foreach ( self::HOT_ONLY_GROUPS as $group => list( $post_types, $keys ) ) {
|
|
$this->assertSame( $post_types, TMDO_Entity_Registry::get_group_post_types( 'post', $group ), $group );
|
|
$this->assertSame( $keys, TMDO_Entity_Registry::get_group_keys( 'post', $group ), $group );
|
|
}
|
|
}
|
|
|
|
public function test_hot_only_fields_route_to_their_group_when_scoped_routing_is_on(): void {
|
|
$GLOBALS['_wp_options'][ TMDO_Entity_Registry::SCOPED_ROUTING_OPTION ] = '1';
|
|
|
|
foreach ( self::HOT_ONLY_GROUPS as $group => list( $post_types, $keys ) ) {
|
|
foreach ( $post_types as $post_type ) {
|
|
foreach ( $keys as $key ) {
|
|
$this->assertSame( $group, TMDO_Entity_Registry::get_field( 'post', $key, $post_type )['group'], "{$post_type}:{$key}" );
|
|
}
|
|
}
|
|
}
|
|
$this->assertSame( 'hp_listing_core', TMDO_Entity_Registry::get_field( 'post', 'hp_expired_time', 'hp_listing' )['group'] );
|
|
}
|
|
|
|
public function test_hot_only_groups_add_no_collisions(): void {
|
|
$this->assertSame( array(), TMDO_Entity_Registry::get_collisions() );
|
|
}
|
|
|
|
public function test_reconciler_plans_the_misrouted_hivepress_keys(): void {
|
|
$moves = array();
|
|
foreach ( TMDO_Post_Group_Reconciler::plan() as $m ) {
|
|
$moves[] = "{$m['source']}>{$m['target']}:{$m['key']}";
|
|
}
|
|
sort( $moves );
|
|
|
|
$this->assertSame(
|
|
array(
|
|
'hp_request_core>hp_listing_core:hp_expired_time',
|
|
'hp_request_core>hp_listing_core:hp_status',
|
|
'hp_request_core>hp_listing_core:hp_view_count',
|
|
'hp_request_core>hp_membership_core:hp_expired_time',
|
|
'hp_vendor_core>hp_listing_core:hp_hourly_rate',
|
|
'hp_vendor_core>hp_listing_core:hp_rating',
|
|
'hp_vendor_core>hp_listing_core:hp_rating_count',
|
|
'hp_vendor_core>hp_listing_core:hp_verified',
|
|
'hp_vendor_core>hp_request_core:hp_user',
|
|
),
|
|
$moves
|
|
);
|
|
}
|
|
|
|
public function test_rest_listings_default_to_hivepress_listings(): void {
|
|
TMDO_HivePress_Entity_Groups::register();
|
|
|
|
$this->assertSame( 'hp_listing', TMDO_REST_API::default_post_type() );
|
|
}
|
|
|
|
public function test_core_adapter_does_not_register_a_conflicting_group(): void {
|
|
( new TMDO_HivePress_Core_Adapter() )->on_register_entity_fields();
|
|
|
|
$this->assertSame( array(), TMDO_Entity_Registry::get_collisions() );
|
|
}
|
|
}
|