initial arhitectural overhaul
Signed-off-by: Sienna Meridian Satterwhite <sienna@r3t.io>
This commit is contained in:
234
crates/libmarathon/tests/bridge_integration.rs
Normal file
234
crates/libmarathon/tests/bridge_integration.rs
Normal file
@@ -0,0 +1,234 @@
|
||||
//! Integration tests for EngineBridge command/event routing
|
||||
|
||||
use libmarathon::engine::{EngineBridge, EngineCommand, EngineCore, EngineEvent};
|
||||
use libmarathon::networking::SessionId;
|
||||
use std::time::Duration;
|
||||
use tokio::time::timeout;
|
||||
|
||||
/// Test that commands sent from "Bevy side" reach the engine
|
||||
#[tokio::test]
|
||||
async fn test_command_routing() {
|
||||
let (bridge, handle) = EngineBridge::new();
|
||||
|
||||
// Spawn engine in background
|
||||
let engine_handle = tokio::spawn(async move {
|
||||
// Run engine for a short time
|
||||
let core = EngineCore::new(handle, ":memory:");
|
||||
timeout(Duration::from_millis(100), core.run())
|
||||
.await
|
||||
.ok();
|
||||
});
|
||||
|
||||
// Give engine time to start
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
|
||||
// Send a command from "Bevy side"
|
||||
let session_id = SessionId::new();
|
||||
bridge.send_command(EngineCommand::StartNetworking {
|
||||
session_id: session_id.clone(),
|
||||
});
|
||||
|
||||
// Give engine time to process
|
||||
tokio::time::sleep(Duration::from_millis(50)).await;
|
||||
|
||||
// Poll events
|
||||
let events = bridge.poll_events();
|
||||
|
||||
// Verify we got a NetworkingStarted event
|
||||
assert!(!events.is_empty(), "Should receive at least one event");
|
||||
|
||||
let has_networking_started = events.iter().any(|e| {
|
||||
matches!(
|
||||
e,
|
||||
EngineEvent::NetworkingStarted {
|
||||
session_id: sid,
|
||||
..
|
||||
} if sid == &session_id
|
||||
)
|
||||
});
|
||||
|
||||
assert!(
|
||||
has_networking_started,
|
||||
"Should receive NetworkingStarted event"
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
drop(bridge);
|
||||
let _ = engine_handle.await;
|
||||
}
|
||||
|
||||
/// Test that events from engine reach "Bevy side"
|
||||
#[tokio::test]
|
||||
async fn test_event_routing() {
|
||||
let (bridge, handle) = EngineBridge::new();
|
||||
|
||||
// Spawn engine
|
||||
let engine_handle = tokio::spawn(async move {
|
||||
let core = EngineCore::new(handle, ":memory:");
|
||||
timeout(Duration::from_millis(100), core.run())
|
||||
.await
|
||||
.ok();
|
||||
});
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
|
||||
// Send StartNetworking command
|
||||
let session_id = SessionId::new();
|
||||
bridge.send_command(EngineCommand::StartNetworking {
|
||||
session_id: session_id.clone(),
|
||||
});
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(50)).await;
|
||||
|
||||
// Poll events multiple times to verify queue works
|
||||
let events1 = bridge.poll_events();
|
||||
let events2 = bridge.poll_events();
|
||||
|
||||
assert!(!events1.is_empty(), "First poll should return events");
|
||||
assert!(
|
||||
events2.is_empty(),
|
||||
"Second poll should be empty (events already drained)"
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
drop(bridge);
|
||||
let _ = engine_handle.await;
|
||||
}
|
||||
|
||||
/// Test full lifecycle: Start → Stop networking
|
||||
#[tokio::test]
|
||||
async fn test_networking_lifecycle() {
|
||||
let (bridge, handle) = EngineBridge::new();
|
||||
|
||||
let engine_handle = tokio::spawn(async move {
|
||||
let core = EngineCore::new(handle, ":memory:");
|
||||
timeout(Duration::from_millis(200), core.run())
|
||||
.await
|
||||
.ok();
|
||||
});
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
|
||||
// Start networking
|
||||
let session_id = SessionId::new();
|
||||
bridge.send_command(EngineCommand::StartNetworking {
|
||||
session_id: session_id.clone(),
|
||||
});
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(50)).await;
|
||||
|
||||
let events = bridge.poll_events();
|
||||
assert!(
|
||||
events
|
||||
.iter()
|
||||
.any(|e| matches!(e, EngineEvent::NetworkingStarted { .. })),
|
||||
"Should receive NetworkingStarted"
|
||||
);
|
||||
|
||||
// Stop networking
|
||||
bridge.send_command(EngineCommand::StopNetworking);
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(50)).await;
|
||||
|
||||
let events = bridge.poll_events();
|
||||
assert!(
|
||||
events
|
||||
.iter()
|
||||
.any(|e| matches!(e, EngineEvent::NetworkingStopped)),
|
||||
"Should receive NetworkingStopped"
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
drop(bridge);
|
||||
let _ = engine_handle.await;
|
||||
}
|
||||
|
||||
/// Test JoinSession command routing
|
||||
#[tokio::test]
|
||||
async fn test_join_session_routing() {
|
||||
let (bridge, handle) = EngineBridge::new();
|
||||
|
||||
let engine_handle = tokio::spawn(async move {
|
||||
let core = EngineCore::new(handle, ":memory:");
|
||||
timeout(Duration::from_millis(200), core.run())
|
||||
.await
|
||||
.ok();
|
||||
});
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
|
||||
// Join a new session (should start networking)
|
||||
let session_id = SessionId::new();
|
||||
bridge.send_command(EngineCommand::JoinSession {
|
||||
session_id: session_id.clone(),
|
||||
});
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(50)).await;
|
||||
|
||||
let events = bridge.poll_events();
|
||||
assert!(
|
||||
events.iter().any(|e| {
|
||||
matches!(
|
||||
e,
|
||||
EngineEvent::NetworkingStarted {
|
||||
session_id: sid,
|
||||
..
|
||||
} if sid == &session_id
|
||||
)
|
||||
}),
|
||||
"JoinSession should start networking"
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
drop(bridge);
|
||||
let _ = engine_handle.await;
|
||||
}
|
||||
|
||||
/// Test that multiple commands are processed in order
|
||||
#[tokio::test]
|
||||
async fn test_command_ordering() {
|
||||
let (bridge, handle) = EngineBridge::new();
|
||||
|
||||
let engine_handle = tokio::spawn(async move {
|
||||
let core = EngineCore::new(handle, ":memory:");
|
||||
timeout(Duration::from_millis(200), core.run())
|
||||
.await
|
||||
.ok();
|
||||
});
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
|
||||
// Send multiple commands
|
||||
let session1 = SessionId::new();
|
||||
let session2 = SessionId::new();
|
||||
|
||||
bridge.send_command(EngineCommand::StartNetworking {
|
||||
session_id: session1.clone(),
|
||||
});
|
||||
bridge.send_command(EngineCommand::StopNetworking);
|
||||
bridge.send_command(EngineCommand::JoinSession {
|
||||
session_id: session2.clone(),
|
||||
});
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||
|
||||
let events = bridge.poll_events();
|
||||
|
||||
// Should see: NetworkingStarted(session1), NetworkingStopped, NetworkingStarted(session2)
|
||||
let started_events: Vec<_> = events
|
||||
.iter()
|
||||
.filter(|e| matches!(e, EngineEvent::NetworkingStarted { .. }))
|
||||
.collect();
|
||||
|
||||
let stopped_events: Vec<_> = events
|
||||
.iter()
|
||||
.filter(|e| matches!(e, EngineEvent::NetworkingStopped))
|
||||
.collect();
|
||||
|
||||
assert_eq!(started_events.len(), 2, "Should have 2 NetworkingStarted events");
|
||||
assert_eq!(stopped_events.len(), 1, "Should have 1 NetworkingStopped event");
|
||||
|
||||
// Cleanup
|
||||
drop(bridge);
|
||||
let _ = engine_handle.await;
|
||||
}
|
||||
Reference in New Issue
Block a user