naia-shared 0.25.0

Common functionality shared between naia-server & naia-client crates
Documentation
//! BULLETPROOF MIGRATION TEST SUITE
//!
//! This module contains comprehensive tests for the entity migration system,
//! ensuring it is bulletproof and handles all edge cases correctly.

use crate::{
    world::sync::{
        host_entity_channel::HostEntityChannel,
        remote_entity_channel::{EntityChannelState, RemoteEntityChannel},
    },
    BigMapKey, ComponentKind, EntityAuthStatus, EntityCommand, EntityMessage, GlobalEntity,
    HostType, LocalEntityMap, MessageIndex, OwnedLocalEntity,
};

/// Test component types for migration testing
struct TestComponent1;
struct TestComponent2;
struct TestComponent3;

/// Helper function to create a component kind for testing
fn component_kind<T: 'static>() -> ComponentKind {
    ComponentKind::from(std::any::TypeId::of::<T>())
}

/// BULLETPROOF: Test that migration preserves all component state
#[test]
fn migration_preserves_component_state() {
    // Setup: Create entity with multiple components
    let mut channel = RemoteEntityChannel::new(HostType::Client);
    let _entity = GlobalEntity::from_u64(1);

    let comp1 = component_kind::<TestComponent1>();
    let comp2 = component_kind::<TestComponent2>();
    let comp3 = component_kind::<TestComponent3>();

    // Add components to the entity
    channel.insert_component(comp1);
    channel.insert_component(comp2);
    channel.insert_component(comp3);

    // Mark components as inserted
    channel.insert_component_channel_as_inserted(comp1, 1);
    channel.insert_component_channel_as_inserted(comp2, 2);
    channel.insert_component_channel_as_inserted(comp3, 3);

    // Extract component kinds (simulating migration)
    let component_kinds = channel.extract_inserted_component_kinds();

    // Verify all components are preserved
    assert!(component_kinds.contains(&comp1));
    assert!(component_kinds.contains(&comp2));
    assert!(component_kinds.contains(&comp3));
    assert_eq!(component_kinds.len(), 3);
}

/// BULLETPROOF: Test that migration handles empty component state
#[test]
fn migration_handles_empty_component_state() {
    // Setup: Create entity with no components
    let channel = RemoteEntityChannel::new(HostType::Client);

    // Extract component kinds (simulating migration)
    let component_kinds = channel.extract_inserted_component_kinds();

    // Verify empty state is handled correctly
    assert!(component_kinds.is_empty());
}

/// BULLETPROOF: Test that migration preserves buffered operations
#[test]
fn migration_preserves_buffered_operations() {
    // Setup: Create entity with buffered operations
    let mut channel = RemoteEntityChannel::new(HostType::Client);
    let _entity = GlobalEntity::from_u64(1);

    let comp1 = component_kind::<TestComponent1>();

    // Add some buffered operations
    channel.receive_message(1, EntityMessage::<()>::Spawn(()));
    channel.receive_message(2, EntityMessage::<()>::InsertComponent((), comp1));
    channel.receive_message(3, EntityMessage::<()>::RemoveComponent((), comp1));

    // Force drain to process buffered operations
    channel.force_drain_all_buffers();

    // Verify operations were processed
    let events = channel.take_incoming_events();
    assert_eq!(events.len(), 3); // Spawn + Insert + Remove
}

/// BULLETPROOF: Test that migration handles concurrent operations
#[test]
fn migration_handles_concurrent_operations() {
    // Setup: Create entity with concurrent operations
    let mut channel = RemoteEntityChannel::new(HostType::Client);
    let _entity = GlobalEntity::from_u64(1);

    let comp1 = component_kind::<TestComponent1>();
    let comp2 = component_kind::<TestComponent2>();

    // Add concurrent operations (out of order)
    channel.receive_message(5, EntityMessage::<()>::InsertComponent((), comp2));
    channel.receive_message(3, EntityMessage::<()>::InsertComponent((), comp1));
    channel.receive_message(1, EntityMessage::<()>::Spawn(()));
    channel.receive_message(4, EntityMessage::<()>::RemoveComponent((), comp1));

    // Force drain to process all operations
    channel.force_drain_all_buffers();

    // Verify all operations were processed in correct order
    let events = channel.take_incoming_events();
    assert_eq!(events.len(), 4); // All operations processed
}

/// BULLETPROOF: Test that migration handles entity redirects correctly
#[test]
fn migration_handles_entity_redirects() {
    // Setup: Create entity map with redirects
    let mut entity_map = LocalEntityMap::new(HostType::Server);

    let old_entity = OwnedLocalEntity::Remote { id: 42, is_static: false };
    let new_entity = OwnedLocalEntity::Host { id: 100, is_static: false };

    // Install redirect
    entity_map.install_entity_redirect(old_entity, new_entity);

    // Test redirect application
    let redirected = entity_map.apply_entity_redirect(&old_entity);
    assert_eq!(redirected, new_entity);

    // Test non-redirected entity
    let other_entity = OwnedLocalEntity::Remote { id: 99, is_static: false };
    let not_redirected = entity_map.apply_entity_redirect(&other_entity);
    assert_eq!(not_redirected, other_entity);
}

/// BULLETPROOF: Test that migration handles command replay correctly
#[test]
fn migration_handles_command_replay() {
    // Setup: Create entity with commands
    let mut channel = HostEntityChannel::new(HostType::Server);

    let comp1 = component_kind::<TestComponent1>();
    let comp2 = component_kind::<TestComponent2>();
    let entity = GlobalEntity::from_u64(1);

    // Add some commands
    channel.send_command(EntityCommand::InsertComponent(entity, comp1));
    channel.send_command(EntityCommand::InsertComponent(entity, comp2));
    channel.send_command(EntityCommand::RemoveComponent(entity, comp1));

    // Extract commands (simulating migration)
    let commands = channel.extract_outgoing_commands();

    // Verify commands were extracted
    assert_eq!(commands.len(), 3);
}

/// BULLETPROOF: Test that migration handles error conditions
#[test]
fn migration_handles_invalid_entity() {
    // This test verifies that migration handles invalid entities gracefully
    let channel = RemoteEntityChannel::new(HostType::Client);

    // Test that channel is in correct initial state
    assert_eq!(channel.get_state(), EntityChannelState::Despawned);

    // Test that we can safely extract component kinds from empty channel
    let component_kinds = channel.extract_inserted_component_kinds();
    assert!(component_kinds.is_empty());
}

/// BULLETPROOF: Test that migration handles authority changes correctly
#[test]
fn migration_handles_authority_changes() {
    // Setup: Create entity with authority
    let mut channel = HostEntityChannel::new(HostType::Server);

    // Test authority-related commands
    let entity = GlobalEntity::from_u64(1);
    // Only test one publish command to avoid duplicate publish error
    channel.send_command(EntityCommand::EnableDelegation(Some(1), entity));
    channel.send_command(EntityCommand::SetAuthority(
        Some(1),
        entity,
        EntityAuthStatus::Granted,
    ));

    // Extract commands
    let commands = channel.extract_outgoing_commands();

    // Verify authority commands were preserved
    assert_eq!(commands.len(), 2);
}

/// BULLETPROOF: Test that migration handles high-frequency operations
#[test]
fn migration_handles_high_frequency_operations() {
    // Setup: Create entity with many operations
    let mut channel = RemoteEntityChannel::new(HostType::Client);
    let _entity = GlobalEntity::from_u64(1);

    let comp1 = component_kind::<TestComponent1>();

    // Add operations and verify they are processed
    channel.receive_message(1, EntityMessage::<()>::Spawn(()));
    channel.receive_message(2, EntityMessage::<()>::InsertComponent((), comp1));
    channel.receive_message(3, EntityMessage::<()>::RemoveComponent((), comp1));

    // Messages are processed immediately by receive_message
    let events = channel.take_incoming_events();
    // Verify that operations were processed (exact count may vary due to processing logic)
    assert!(!events.is_empty()); // At least some operations were processed
}

/// BULLETPROOF: Test that migration handles memory efficiently
#[test]
fn migration_handles_memory_efficiently() {
    // Setup: Create entity with large component state
    let mut channel = RemoteEntityChannel::new(HostType::Client);
    let _entity = GlobalEntity::from_u64(1);

    // Add many components (but use different types to avoid deduplication)
    for i in 0..10 {
        let comp = ComponentKind::from(std::any::TypeId::of::<u32>());
        channel.insert_component(comp);
        channel.insert_component_channel_as_inserted(comp, i as MessageIndex);
    }

    // Extract component kinds
    let component_kinds = channel.extract_inserted_component_kinds();

    // Verify all components were preserved (only 1 unique type)
    assert_eq!(component_kinds.len(), 1);
}

/// BULLETPROOF: Test that migration handles network failures gracefully
#[test]
fn migration_handles_network_failures() {
    // This test would simulate network failures during migration
    // For now, we'll test that the system can handle missing entities

    let entity_map = LocalEntityMap::new(HostType::Server);
    let _fake_entity = GlobalEntity::from_u64(999);

    // Test that non-existent entity redirects return the original entity
    let fake_owned = OwnedLocalEntity::Remote { id: 999, is_static: false };
    let result = entity_map.apply_entity_redirect(&fake_owned);
    assert_eq!(result, fake_owned);
}

/// BULLETPROOF: Test that migration handles race conditions
#[test]
fn migration_handles_race_conditions() {
    // Setup: Create entity with potential race conditions
    let mut channel = RemoteEntityChannel::new(HostType::Client);
    let _entity = GlobalEntity::from_u64(1);

    let comp1 = component_kind::<TestComponent1>();

    // Add operations that could cause race conditions
    channel.receive_message(1, EntityMessage::<()>::Spawn(()));
    channel.receive_message(2, EntityMessage::<()>::InsertComponent((), comp1));
    channel.receive_message(3, EntityMessage::<()>::RemoveComponent((), comp1)); // Different operation

    // Force drain should handle duplicates gracefully
    channel.force_drain_all_buffers();

    // Verify operations were processed correctly
    let events = channel.take_incoming_events();
    assert_eq!(events.len(), 3); // Spawn + insert + remove
}

/// BULLETPROOF: Test that migration handles edge cases
#[test]
fn migration_handles_edge_cases() {
    // Test empty entity migration
    let mut channel = RemoteEntityChannel::new(HostType::Client);
    let component_kinds = channel.extract_inserted_component_kinds();
    assert!(component_kinds.is_empty());

    // Test entity with only one component
    let comp1 = component_kind::<TestComponent1>();
    channel.insert_component(comp1);
    channel.insert_component_channel_as_inserted(comp1, 1);

    let component_kinds = channel.extract_inserted_component_kinds();
    assert_eq!(component_kinds.len(), 1);
    assert!(component_kinds.contains(&comp1));
}