use super::*;
use crate::packet_channel;
use std::sync::atomic::{AtomicBool, Ordering};
#[test]
fn validates_compressed_pubkey_addresses() {
let good = "02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
assert!(validate_compressed_pubkey_hex(good).is_ok());
assert!(validate_compressed_pubkey_hex(&good[2..]).is_err());
assert!(
validate_compressed_pubkey_hex(
"04aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
)
.is_err()
);
}
#[test]
fn webrtc_signal_serializes_like_ts_transport() {
let signal = WebRtcSignal {
protocol: WEBRTC_PROTOCOL.to_string(),
version: WEBRTC_SIGNAL_VERSION,
session_id: "abc".to_string(),
kind: WebRtcSignalKind::Offer,
sender: "02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".to_string(),
recipient: "03bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb".to_string(),
sdp: Some("v=0".to_string()),
candidates: None,
created_at_ms: 1,
expires_at_ms: 2,
};
let json = serde_json::to_string(&signal).unwrap();
assert!(json.contains(r#""sessionId":"abc""#));
assert!(json.contains(r#""createdAtMs":1"#));
assert!(json.contains(r#""expiresAtMs":2"#));
}
#[test]
fn disconnected_webrtc_sessions_are_terminal_for_fips() {
for state in [
RTCPeerConnectionState::Disconnected,
RTCPeerConnectionState::Failed,
RTCPeerConnectionState::Closed,
] {
assert!(webrtc_peer_state_is_terminal(state));
}
for state in [
RTCPeerConnectionState::New,
RTCPeerConnectionState::Connecting,
RTCPeerConnectionState::Connected,
] {
assert!(!webrtc_peer_state_is_terminal(state));
}
}
#[tokio::test]
async fn connection_state_does_not_report_none_during_pool_contention() {
let identity = crate::Identity::generate();
let (packet_tx, _packet_rx) = packet_channel(1);
let transport = WebRtcTransport::new(
TransportId::new(1),
None,
WebRtcConfig::default(),
packet_tx,
&identity,
&NostrDiscoveryConfig::default(),
)
.expect("WebRTC transport");
let _pool_guard = transport.pool.lock().await;
let addr = TransportAddr::from_string(
"02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
);
assert_eq!(
transport.connection_state_sync(&addr),
ConnectionState::Connecting
);
}
#[tokio::test]
async fn stalled_webrtc_send_times_out_and_starts_cleanup() {
let cleanup_started = Arc::new(AtomicBool::new(false));
let cleanup_flag = Arc::clone(&cleanup_started);
let started = tokio::time::Instant::now();
let result = bounded_webrtc_send(
Duration::from_millis(10),
std::future::pending::<Result<usize, std::io::Error>>(),
move || async move {
cleanup_flag.store(true, Ordering::SeqCst);
std::future::pending::<()>().await;
},
)
.await;
assert!(matches!(result, Err(TransportError::Timeout)));
assert!(cleanup_started.load(Ordering::SeqCst));
assert!(started.elapsed() < Duration::from_millis(100));
}
#[tokio::test]
async fn terminal_session_cleanup_closes_the_peer_connection() {
let identity = crate::Identity::generate();
let (packet_tx, _packet_rx) = packet_channel(1);
let transport = WebRtcTransport::new(
TransportId::new(1),
None,
WebRtcConfig::default(),
packet_tx,
&identity,
&NostrDiscoveryConfig::default(),
)
.expect("WebRTC transport");
let pc = Arc::new(
transport
.api
.new_peer_connection(RTCConfiguration::default())
.await
.expect("peer connection"),
);
let data_channel = pc
.create_data_channel("cleanup-test", None)
.await
.expect("data channel");
let addr = TransportAddr::from_string(
"02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
);
transport.pool.lock().await.insert(
addr.clone(),
WebRtcConnection {
session_id: "cleanup-session".to_string(),
pc: Arc::clone(&pc),
data_channel,
},
);
transport.ready.lock().await.insert(addr.clone());
let removed = cleanup_webrtc_session(
&transport.pool,
&transport.pending,
&transport.failed,
&transport.ready,
&addr,
Some("cleanup-session"),
Some("peer disconnected".to_string()),
)
.await;
assert!(removed);
assert!(!transport.pool.lock().await.contains_key(&addr));
assert!(!transport.ready.lock().await.contains(&addr));
assert_eq!(
transport.failed.lock().await.get(&addr).map(String::as_str),
Some("peer disconnected")
);
assert_eq!(pc.connection_state(), RTCPeerConnectionState::Closed);
}