use std::sync::Arc;
use crate::config::RtcConfig;
use crate::session::{CallSession, SessionEventReceiver};
use crate::types::{CallState, RtcEvent, SignalingMessage};
use crate::MockWebRtcEngine;
async fn read_events<R>(receiver: &R, count: usize) -> Vec<RtcEvent>
where
R: SessionEventReceiver + Sync,
{
let mut items = Vec::new();
for _ in 0..count {
if let Ok(event) = receiver.recv_event().await {
items.push(event);
}
}
items
}
#[tokio::test]
async fn outgoing_call_reaches_connected() {
let config = RtcConfig::default();
let engine = Arc::new(MockWebRtcEngine::new());
let session = CallSession::with_engine(config, engine.clone()).unwrap();
let offer = session.create_offer().unwrap();
match offer {
SignalingMessage::Offer { .. } => {}
_ => panic!("unexpected offer"),
}
assert_eq!(session.state(), CallState::WaitingAnswer);
session.accept_answer("remote-answer").unwrap();
assert_eq!(session.state(), CallState::Connected);
let events = read_events(&session, 4).await;
assert!(events
.iter()
.any(|e| matches!(e, RtcEvent::StateChanged(CallState::CreatingOffer))));
assert!(events
.iter()
.any(|e| matches!(e, RtcEvent::StateChanged(CallState::WaitingAnswer))));
assert!(events
.iter()
.any(|e| matches!(e, RtcEvent::ConnectionEstablished)));
engine.emit_candidate("local").unwrap();
let candidate_event = session.next_event().await.unwrap();
match candidate_event {
RtcEvent::LocalIceCandidate(SignalingMessage::IceCandidate { .. }) => {}
_ => panic!("missing candidate"),
}
}
#[tokio::test]
async fn incoming_call_transitions() {
let config = RtcConfig::default();
let engine = Arc::new(MockWebRtcEngine::new());
let session = CallSession::with_engine(config, engine).unwrap();
let answer = session.accept_offer("remote-offer").unwrap();
match answer {
SignalingMessage::Answer { .. } => {}
_ => panic!("unexpected answer"),
}
assert_eq!(session.state(), CallState::Connected);
let events = read_events(&session, 3).await;
assert!(events
.iter()
.any(|e| matches!(e, RtcEvent::StateChanged(CallState::IncomingOffer))));
assert!(events
.iter()
.any(|e| matches!(e, RtcEvent::StateChanged(CallState::Connected))));
assert!(events
.iter()
.any(|e| matches!(e, RtcEvent::ConnectionEstablished)));
}
#[tokio::test]
async fn hangup_emits_closed_event() {
let config = RtcConfig::default();
let engine = Arc::new(MockWebRtcEngine::new());
let session = CallSession::with_engine(config, engine).unwrap();
session.create_offer().unwrap();
session.accept_answer("remote-answer").unwrap();
let hangup = session.hangup(Some("done")).unwrap();
match hangup {
SignalingMessage::Hangup { reason } => assert_eq!(reason, Some("done".to_string())),
_ => panic!("unexpected hangup"),
}
assert_eq!(session.state(), CallState::Ended);
let events = read_events(&session, 7).await;
assert!(events
.iter()
.any(|e| matches!(e, RtcEvent::StateChanged(CallState::Ending))));
assert!(events
.iter()
.any(|e| matches!(e, RtcEvent::StateChanged(CallState::Ended))));
assert!(events
.iter()
.any(|e| matches!(e, RtcEvent::ConnectionClosed)));
}