mirror of
https://github.com/telemt/telemt.git
synced 2026-09-19 08:52:48 +03:00
WEB Carriers Safe-matrix Refactored
Co-Authored-By: brekotis <93345790+brekotis@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
use super::*;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use arc_swap::ArcSwap;
|
||||
|
||||
use crate::config::{
|
||||
ProxyConfig, WebCarrier, WebLimitsConfig, WebRuntimeProfile, WebSecretMode,
|
||||
WebTimeoutsConfig,
|
||||
};
|
||||
use crate::maestro::generation::test_runtime_generation;
|
||||
use crate::web::manager::WebProcessRuntime;
|
||||
|
||||
fn session() -> (Arc<WebSession>, Arc<WebProcessRuntime>) {
|
||||
let generation = test_runtime_generation(1, ProxyConfig::default());
|
||||
let manager = WebProcessRuntime::start(Arc::new(ArcSwap::from(generation)));
|
||||
let profile = Arc::new(WebRuntimeProfile {
|
||||
host: "proxy.example.com".to_string(),
|
||||
public_addr: SocketAddr::from(([203, 0, 113, 10], 443)),
|
||||
user: "alice".to_string(),
|
||||
secret_mode: WebSecretMode::Plain,
|
||||
carrier: WebCarrier::Https,
|
||||
carrier_negotiation_enabled: false,
|
||||
carrier_learning: false,
|
||||
carriers: Arc::from([WebCarrier::Https]),
|
||||
carrier_negotiation_deadlines_secs: [3, 5, 8, 12],
|
||||
capability: [0; 32],
|
||||
key_fingerprint: "0000000000000000".to_string(),
|
||||
max_sessions: 1,
|
||||
max_streams: 1,
|
||||
max_streams_per_session: 1,
|
||||
});
|
||||
let mut timeouts = WebTimeoutsConfig::default();
|
||||
timeouts.long_poll_secs = 1;
|
||||
let session = WebSession::new(
|
||||
Arc::downgrade(&manager),
|
||||
[1; 32],
|
||||
"192.0.2.10".parse().unwrap(),
|
||||
1,
|
||||
profile,
|
||||
[2; 32],
|
||||
WebCarrier::Https,
|
||||
1,
|
||||
[3; 32],
|
||||
None,
|
||||
crate::web::manager::CarrierClientClass::Legacy,
|
||||
None,
|
||||
false,
|
||||
WebLimitsConfig::default(),
|
||||
timeouts,
|
||||
);
|
||||
(session, manager)
|
||||
}
|
||||
|
||||
fn queue_close(session: &WebSession) {
|
||||
let mut state = session.state.lock();
|
||||
assert!(session.queue_control_locked(&mut state, FrameType::Close, 1, &[]));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn downlink_replays_unacknowledged_batch_byte_for_byte() {
|
||||
let (session, manager) = session();
|
||||
queue_close(&session);
|
||||
let first = session.poll_down(0).await.unwrap();
|
||||
let replay = session.poll_down(0).await.unwrap();
|
||||
assert_eq!(first.next_cursor, 1);
|
||||
assert_eq!(replay.next_cursor, 1);
|
||||
assert_eq!(first.body, replay.body);
|
||||
drop(first);
|
||||
drop(replay);
|
||||
session.close();
|
||||
manager.shutdown().await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn acknowledged_response_stays_resident_until_the_last_body_clone_drops() {
|
||||
let (session, manager) = session();
|
||||
queue_close(&session);
|
||||
let response = session.poll_down(0).await.unwrap();
|
||||
let retained = response.body.clone();
|
||||
{
|
||||
let mut state = session.state.lock();
|
||||
session.release_unacked_locked(&mut state);
|
||||
assert_eq!(state.pending_bytes, 0);
|
||||
}
|
||||
assert!(session.resident.snapshot().bytes() > 0);
|
||||
drop(response);
|
||||
assert!(session.resident.snapshot().bytes() > 0);
|
||||
drop(retained);
|
||||
assert_eq!(session.resident.snapshot().bytes(), 0);
|
||||
session.close();
|
||||
manager.shutdown().await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn invalid_or_overflowing_cursor_closes_session() {
|
||||
let (invalid, invalid_manager) = session();
|
||||
assert!(matches!(
|
||||
invalid.poll_down(1).await,
|
||||
Err(ManagerError::Protocol)
|
||||
));
|
||||
assert!(invalid.state.lock().closed);
|
||||
invalid_manager.shutdown().await;
|
||||
|
||||
let (overflow, overflow_manager) = session();
|
||||
{
|
||||
let mut state = overflow.state.lock();
|
||||
state.down_cursor = u64::MAX;
|
||||
}
|
||||
queue_close(&overflow);
|
||||
assert!(matches!(
|
||||
overflow.poll_down(u64::MAX).await,
|
||||
Err(ManagerError::Protocol)
|
||||
));
|
||||
assert!(overflow.state.lock().closed);
|
||||
overflow_manager.shutdown().await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn newer_poll_supersedes_older_poll_without_closing_session() {
|
||||
let (session, manager) = session();
|
||||
let first_session = Arc::clone(&session);
|
||||
let first = tokio::spawn(async move { first_session.poll_down(0).await });
|
||||
while session.state.lock().down_epoch < 1 {
|
||||
tokio::task::yield_now().await;
|
||||
}
|
||||
let second_session = Arc::clone(&session);
|
||||
let second = tokio::spawn(async move { second_session.poll_down(0).await });
|
||||
while session.state.lock().down_epoch < 2 {
|
||||
tokio::task::yield_now().await;
|
||||
}
|
||||
let superseded = tokio::time::timeout(Duration::from_secs(1), first)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert!(superseded.body.is_empty());
|
||||
assert_eq!(superseded.next_cursor, 0);
|
||||
assert!(!session.state.lock().closed);
|
||||
second.abort();
|
||||
session.close();
|
||||
manager.shutdown().await;
|
||||
}
|
||||
Reference in New Issue
Block a user