use std::sync::Arc;
use crate::auth::AuthHandler;
use crate::config::RoutingMode;
use crate::metrics::MetricsCollector;
use crate::pool::BufferPool;
use crate::router::BackendSelector;
use crate::types::{ClientAddress, ClientId};
use super::{AuthState, ModeState, SessionMode};
pub struct ClientSession {
pub(super) client_addr: ClientAddress,
pub(super) buffer_pool: BufferPool,
pub(super) client_id: ClientId,
pub(super) router: Option<Arc<BackendSelector>>,
pub(super) mode_state: ModeState,
pub(super) auth_handler: Arc<AuthHandler>,
pub(super) auth_state: AuthState,
pub(super) metrics: crate::metrics::MetricsCollector,
pub(super) connection_stats: Option<crate::metrics::ConnectionStatsAggregator>,
pub(super) cache: Arc<crate::cache::UnifiedCache>,
pub(super) cache_articles: bool,
pub(super) adaptive_precheck: bool,
}
pub struct ClientSessionBuilder {
client_addr: ClientAddress,
buffer_pool: BufferPool,
router: Option<Arc<BackendSelector>>,
routing_mode: RoutingMode,
auth_handler: Arc<AuthHandler>,
metrics: MetricsCollector,
connection_stats: Option<crate::metrics::ConnectionStatsAggregator>,
cache: BuilderCache,
cache_articles: bool,
adaptive_precheck: bool,
}
enum BuilderCache {
DefaultAvailability,
Shared(Arc<crate::cache::UnifiedCache>),
}
impl BuilderCache {
fn into_cache(self) -> Arc<crate::cache::UnifiedCache> {
match self {
Self::DefaultAvailability => ClientSession::default_cache(),
Self::Shared(cache) => cache,
}
}
}
impl ClientSessionBuilder {
#[must_use]
pub fn with_router(mut self, router: Arc<BackendSelector>) -> Self {
self.router = Some(router);
self
}
#[must_use]
pub const fn with_routing_mode(mut self, mode: RoutingMode) -> Self {
self.routing_mode = mode;
self
}
#[must_use]
pub fn with_auth_handler(mut self, auth_handler: Arc<AuthHandler>) -> Self {
self.auth_handler = auth_handler;
self
}
#[must_use]
pub fn with_connection_stats(
mut self,
connection_stats: crate::metrics::ConnectionStatsAggregator,
) -> Self {
self.connection_stats = Some(connection_stats);
self
}
#[must_use]
pub fn with_cache(mut self, cache: Arc<crate::cache::UnifiedCache>) -> Self {
self.cache = BuilderCache::Shared(cache);
self
}
#[must_use]
pub const fn with_cache_articles(mut self, cache: bool) -> Self {
self.cache_articles = cache;
self
}
#[must_use]
pub const fn with_adaptive_precheck(mut self, enable: bool) -> Self {
self.adaptive_precheck = enable;
self
}
#[must_use]
pub fn build(self) -> ClientSession {
let (mode, routing_mode) = match (&self.router, self.routing_mode) {
(Some(_), RoutingMode::PerCommand | RoutingMode::Hybrid) => {
(SessionMode::PerCommand, self.routing_mode)
}
(Some(_), RoutingMode::Stateful) | (None, _) => {
(SessionMode::Stateful, RoutingMode::Stateful)
}
};
ClientSession {
client_addr: self.client_addr,
buffer_pool: self.buffer_pool,
client_id: ClientId::new(),
router: self.router,
mode_state: ModeState::new(mode, routing_mode),
auth_handler: self.auth_handler,
auth_state: AuthState::new(),
metrics: self.metrics,
connection_stats: self.connection_stats,
cache: self.cache.into_cache(),
cache_articles: self.cache_articles,
adaptive_precheck: self.adaptive_precheck,
}
}
}
impl ClientSession {
fn default_cache() -> Arc<crate::cache::UnifiedCache> {
Arc::new(crate::cache::UnifiedCache::availability(
std::time::Duration::MAX,
))
}
#[must_use]
pub fn new(
client_addr: ClientAddress,
buffer_pool: BufferPool,
auth_handler: Arc<AuthHandler>,
metrics: MetricsCollector,
) -> Self {
Self {
client_addr,
buffer_pool,
client_id: ClientId::new(),
router: None,
mode_state: ModeState::new(SessionMode::Stateful, RoutingMode::Stateful),
auth_handler,
auth_state: AuthState::new(),
metrics,
connection_stats: None,
cache: Self::default_cache(),
cache_articles: false,
adaptive_precheck: false,
}
}
#[must_use]
pub fn new_with_router(
client_addr: ClientAddress,
buffer_pool: BufferPool,
router: Arc<BackendSelector>,
routing_mode: RoutingMode,
auth_handler: Arc<AuthHandler>,
metrics: MetricsCollector,
) -> Self {
Self {
client_addr,
buffer_pool,
client_id: ClientId::new(),
router: Some(router),
mode_state: ModeState::new(SessionMode::PerCommand, routing_mode),
auth_handler,
auth_state: AuthState::new(),
metrics,
connection_stats: None,
cache: Self::default_cache(),
cache_articles: false,
adaptive_precheck: false,
}
}
#[must_use]
pub fn builder(
client_addr: ClientAddress,
buffer_pool: BufferPool,
auth_handler: Arc<AuthHandler>,
metrics: MetricsCollector,
) -> ClientSessionBuilder {
ClientSessionBuilder {
client_addr,
buffer_pool,
router: None,
routing_mode: RoutingMode::Stateful,
auth_handler,
metrics,
connection_stats: None,
cache: BuilderCache::DefaultAvailability,
cache_articles: false,
adaptive_precheck: false,
}
}
#[must_use]
#[inline]
pub const fn client_id(&self) -> ClientId {
self.client_id
}
#[must_use]
#[inline]
pub const fn is_per_command_routing(&self) -> bool {
self.router.is_some()
}
#[must_use]
#[inline]
pub fn mode(&self) -> SessionMode {
self.mode_state.mode()
}
#[inline]
#[must_use]
pub fn username(&self) -> Option<&str> {
self.auth_state.username()
}
pub(crate) fn set_username(&self, username: Option<String>) {
if let Some(name) = username {
self.auth_state.mark_authenticated(name);
}
}
#[must_use]
#[inline]
pub(crate) const fn connection_stats(
&self,
) -> Option<&crate::metrics::ConnectionStatsAggregator> {
self.connection_stats.as_ref()
}
#[inline]
pub(crate) fn is_authenticated_cached(&self, skip_auth_check: bool) -> bool {
self.auth_state.is_authenticated_or_skipped(skip_auth_check)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::auth::AuthHandler;
use crate::metrics::MetricsCollector;
use crate::types::BufferSize;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::sync::Arc;
fn test_auth_handler() -> Arc<AuthHandler> {
Arc::new(AuthHandler::new(None, None).unwrap())
}
fn test_metrics() -> MetricsCollector {
MetricsCollector::new(1)
}
#[test]
fn test_client_session_creation() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let session = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
assert_eq!(session.client_addr.port(), 8080);
assert_eq!(session.client_addr.ip(), IpAddr::V4(Ipv4Addr::LOCALHOST));
}
#[test]
fn test_client_session_with_different_ports() {
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let session1 = ClientSession::new(
addr1.into(),
buffer_pool.clone(),
test_auth_handler(),
test_metrics(),
);
let addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9090);
let session2 = ClientSession::new(
addr2.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
assert_ne!(session1.client_addr.port(), session2.client_addr.port());
assert_eq!(session1.client_addr.port(), 8080);
assert_eq!(session2.client_addr.port(), 9090);
}
#[test]
fn test_client_session_with_ipv6() {
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let addr = SocketAddr::new(IpAddr::V6("::1".parse().unwrap()), 8119);
let session = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
assert_eq!(session.client_addr.port(), 8119);
assert!(session.client_addr.is_ipv6());
}
#[test]
fn test_buffer_pool_cloning() {
let buffer_pool = BufferPool::new(BufferSize::try_new(8192).unwrap(), 10);
let buffer_pool_clone = buffer_pool.clone();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 1234);
let _session1 = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
let _session2 = ClientSession::new(
addr.into(),
buffer_pool_clone,
test_auth_handler(),
test_metrics(),
);
}
#[test]
fn test_session_addr_formatting() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)), 5555);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let session = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
let addr_str = format!("{}", session.client_addr);
assert!(addr_str.contains("10.0.0.1"));
assert!(addr_str.contains("5555"));
}
#[test]
fn test_multiple_sessions_same_buffer_pool() {
let buffer_pool = BufferPool::new(BufferSize::try_new(4096).unwrap(), 8);
let sessions: Vec<_> = (0..5)
.map(|i| {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8000 + i);
ClientSession::new(
addr.into(),
buffer_pool.clone(),
test_auth_handler(),
test_metrics(),
)
})
.collect();
assert_eq!(sessions.len(), 5);
for (i, session) in sessions.iter().enumerate() {
assert_eq!(session.client_addr.port(), 8000 + i as u16);
}
}
#[test]
fn test_loopback_address() {
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8119);
let session = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
assert!(session.client_addr.ip().is_loopback());
}
#[test]
fn test_unspecified_address() {
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0);
let session = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
assert!(session.client_addr.ip().is_unspecified());
assert_eq!(session.client_addr.port(), 0);
}
#[test]
fn test_session_without_router() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let session = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
assert!(!session.is_per_command_routing());
assert_eq!(session.client_addr.port(), 8080);
}
#[test]
fn test_session_with_router() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let router = Arc::new(BackendSelector::new());
let session = ClientSession::new_with_router(
addr.into(),
buffer_pool,
router,
RoutingMode::PerCommand,
test_auth_handler(),
test_metrics(),
);
assert!(session.is_per_command_routing());
assert_eq!(session.client_addr.port(), 8080);
}
#[test]
fn test_client_id_uniqueness() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let session1 = ClientSession::new(
addr.into(),
buffer_pool.clone(),
test_auth_handler(),
test_metrics(),
);
let session2 = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
assert_ne!(session1.client_id(), session2.client_id());
}
#[test]
fn test_session_mode_enum() {
assert_eq!(SessionMode::PerCommand, SessionMode::PerCommand);
assert_eq!(SessionMode::Stateful, SessionMode::Stateful);
assert_ne!(SessionMode::PerCommand, SessionMode::Stateful);
let per_command = format!("{:?}", SessionMode::PerCommand);
let stateful = format!("{:?}", SessionMode::Stateful);
assert!(per_command.contains("PerCommand"));
assert!(stateful.contains("Stateful"));
}
#[test]
fn test_hybrid_session_creation() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let router = Arc::new(BackendSelector::new());
let session = ClientSession::new_with_router(
addr.into(),
buffer_pool,
router,
RoutingMode::Hybrid,
test_auth_handler(),
test_metrics(),
);
assert!(session.is_per_command_routing());
assert_eq!(session.mode_state.routing_mode(), RoutingMode::Hybrid);
assert_eq!(session.mode(), SessionMode::PerCommand);
}
#[test]
fn test_routing_mode_configurations() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let router = Arc::new(BackendSelector::new());
let session = ClientSession::new_with_router(
addr.into(),
buffer_pool.clone(),
router.clone(),
RoutingMode::Stateful,
test_auth_handler(),
test_metrics(),
);
assert!(session.is_per_command_routing());
assert_eq!(session.mode_state.routing_mode(), RoutingMode::Stateful);
let session = ClientSession::new_with_router(
addr.into(),
buffer_pool.clone(),
router.clone(),
RoutingMode::PerCommand,
test_auth_handler(),
test_metrics(),
);
assert!(session.is_per_command_routing());
assert_eq!(session.mode_state.routing_mode(), RoutingMode::PerCommand);
assert_eq!(session.mode(), SessionMode::PerCommand);
let session = ClientSession::new_with_router(
addr.into(),
buffer_pool,
router,
RoutingMode::Hybrid,
test_auth_handler(),
test_metrics(),
);
assert!(session.is_per_command_routing());
assert_eq!(session.mode_state.routing_mode(), RoutingMode::Hybrid);
assert_eq!(session.mode(), SessionMode::PerCommand);
}
#[test]
fn test_hybrid_mode_initial_state() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let router = Arc::new(BackendSelector::new());
let session = ClientSession::new_with_router(
addr.into(),
buffer_pool,
router,
RoutingMode::Hybrid,
test_auth_handler(),
test_metrics(),
);
assert_eq!(session.mode(), SessionMode::PerCommand);
assert_eq!(session.mode_state.routing_mode(), RoutingMode::Hybrid);
assert!(session.is_per_command_routing());
}
#[test]
fn test_is_per_command_routing_logic() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let router = Arc::new(BackendSelector::new());
let session = ClientSession::new_with_router(
addr.into(),
buffer_pool.clone(),
router.clone(),
RoutingMode::Stateful,
test_auth_handler(),
test_metrics(),
);
assert!(session.is_per_command_routing());
let session = ClientSession::new_with_router(
addr.into(),
buffer_pool.clone(),
router.clone(),
RoutingMode::PerCommand,
test_auth_handler(),
test_metrics(),
);
assert!(session.is_per_command_routing());
let session = ClientSession::new_with_router(
addr.into(),
buffer_pool.clone(),
router,
RoutingMode::Hybrid,
test_auth_handler(),
test_metrics(),
);
assert!(session.is_per_command_routing());
let session = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
assert!(!session.is_per_command_routing());
}
#[test]
fn test_builder_basic_construction() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let auth_handler = test_auth_handler();
let session =
ClientSession::builder(addr.into(), buffer_pool, auth_handler, test_metrics()).build();
assert_eq!(*session.client_addr, addr);
assert!(!session.is_per_command_routing());
assert_eq!(session.mode(), SessionMode::Stateful);
assert_eq!(session.mode_state.routing_mode(), RoutingMode::Stateful);
}
#[test]
fn test_builder_with_router() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let router = Arc::new(BackendSelector::new());
let session = ClientSession::builder(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
)
.with_router(router)
.with_routing_mode(RoutingMode::PerCommand)
.build();
assert!(session.is_per_command_routing());
assert_eq!(session.mode(), SessionMode::PerCommand);
assert_eq!(session.mode_state.routing_mode(), RoutingMode::PerCommand);
}
#[test]
fn test_builder_with_hybrid_mode() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let router = Arc::new(BackendSelector::new());
let session = ClientSession::builder(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
)
.with_router(router)
.with_routing_mode(RoutingMode::Hybrid)
.build();
assert!(session.is_per_command_routing());
assert_eq!(session.mode(), SessionMode::PerCommand);
assert_eq!(session.mode_state.routing_mode(), RoutingMode::Hybrid);
}
#[test]
fn test_builder_with_stateful_mode() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let router = Arc::new(BackendSelector::new());
let session = ClientSession::builder(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
)
.with_router(router)
.with_routing_mode(RoutingMode::Stateful)
.build();
assert!(session.is_per_command_routing());
assert_eq!(session.mode(), SessionMode::Stateful);
assert_eq!(session.mode_state.routing_mode(), RoutingMode::Stateful);
}
#[test]
fn test_builder_without_router_ignores_mode() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let session = ClientSession::builder(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
)
.with_routing_mode(RoutingMode::PerCommand)
.build();
assert!(!session.is_per_command_routing());
assert_eq!(session.mode(), SessionMode::Stateful);
assert_eq!(session.mode_state.routing_mode(), RoutingMode::Stateful);
}
#[test]
fn test_builder_with_auth_handler() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let auth_handler =
Arc::new(AuthHandler::new(Some("user".to_string()), Some("pass".to_string())).unwrap());
let session = ClientSession::builder(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
)
.with_auth_handler(auth_handler)
.build();
assert_eq!(*session.client_addr, addr);
}
#[test]
fn test_builder_with_metrics() {
use crate::metrics::MetricsCollector;
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let metrics = MetricsCollector::new(1);
let session =
ClientSession::builder(addr.into(), buffer_pool, test_auth_handler(), metrics).build();
let _ = session.metrics; }
#[test]
fn test_builder_with_connection_stats() {
use crate::metrics::ConnectionStatsAggregator;
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let stats = ConnectionStatsAggregator::default();
let session = ClientSession::builder(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
)
.with_connection_stats(stats)
.build();
assert!(session.connection_stats().is_some());
}
#[test]
fn test_builder_with_cache() {
use crate::cache::UnifiedCache;
use std::time::Duration;
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let cache = Arc::new(UnifiedCache::memory(100, Duration::from_secs(3600)));
let session = ClientSession::builder(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
)
.with_cache(cache)
.build();
assert_eq!(session.cache.capacity(), 100);
}
#[test]
fn test_builder_method_chaining() {
use crate::metrics::MetricsCollector;
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let router = Arc::new(BackendSelector::new());
let metrics = MetricsCollector::new(1);
let session =
ClientSession::builder(addr.into(), buffer_pool, test_auth_handler(), metrics)
.with_router(router)
.with_routing_mode(RoutingMode::Hybrid)
.build();
assert!(session.is_per_command_routing());
assert_eq!(session.mode(), SessionMode::PerCommand);
assert_eq!(session.mode_state.routing_mode(), RoutingMode::Hybrid);
let _ = session.metrics; }
#[test]
fn test_mode_getter() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let router = Arc::new(BackendSelector::new());
let session = ClientSession::new_with_router(
addr.into(),
buffer_pool.clone(),
router,
RoutingMode::PerCommand,
test_auth_handler(),
test_metrics(),
);
assert_eq!(session.mode(), SessionMode::PerCommand);
let session = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
assert_eq!(session.mode(), SessionMode::Stateful);
}
#[test]
fn test_username_initially_none() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let session = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
assert!(session.username().is_none());
}
#[test]
fn test_set_username_and_get() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let session = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
session.set_username(Some("testuser".to_string()));
let username = session.username();
assert!(username.is_some());
assert_eq!(username, Some("testuser"));
}
#[test]
fn test_set_username_none() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let session = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
session.set_username(None);
assert!(session.username().is_none());
}
#[test]
fn test_username_cheap_clone() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let session = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
session.set_username(Some("testuser".to_string()));
let username1 = session.username();
let username2 = session.username();
assert!(username1.is_some());
assert!(username2.is_some());
assert_eq!(username1, username2);
assert_eq!(username1, Some("testuser"));
}
#[test]
fn test_connection_stats_none_by_default() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let session = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
assert!(session.connection_stats().is_none());
}
#[test]
fn test_connection_stats_with_aggregator() {
use crate::metrics::ConnectionStatsAggregator;
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let stats = ConnectionStatsAggregator::default();
let session = ClientSession::builder(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
)
.with_connection_stats(stats)
.build();
assert!(session.connection_stats().is_some());
}
#[test]
fn test_metrics_direct_calls_no_metrics() {
use crate::types::BackendId;
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let session = ClientSession::new(
addr.into(),
buffer_pool,
test_auth_handler(),
test_metrics(),
);
session.metrics.record_command(BackendId::from_index(0));
session.metrics.user_command(session.username());
session.metrics.stateful_session_started();
session.metrics.stateful_session_ended();
session.metrics.user_bytes_sent(session.username(), 1024);
session
.metrics
.user_bytes_received(session.username(), 2048);
}
#[test]
fn test_metrics_direct_calls_with_metrics() {
use crate::metrics::MetricsCollector;
use crate::types::BackendId;
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let metrics = MetricsCollector::new(1);
let session = ClientSession::builder(
addr.into(),
buffer_pool,
test_auth_handler(),
metrics.clone(),
)
.build();
session.set_username(Some("testuser".to_string()));
session.metrics.record_command(BackendId::from_index(0));
session.metrics.user_command(session.username());
session.metrics.stateful_session_started();
session.metrics.stateful_session_ended();
session.metrics.user_bytes_sent(session.username(), 1024);
session
.metrics
.user_bytes_received(session.username(), 2048);
let snapshot = metrics.snapshot(None);
assert!(!snapshot.backend_stats.is_empty());
assert!(snapshot.backend_stats[0].total_commands.get() > 0);
}
#[test]
fn test_record_command_with_metrics() {
use crate::metrics::MetricsCollector;
use crate::types::BackendId;
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let metrics = MetricsCollector::new(1);
let session = ClientSession::builder(
addr.into(),
buffer_pool,
test_auth_handler(),
metrics.clone(),
)
.build();
let backend_id = BackendId::from_index(0);
session.metrics.record_command(backend_id);
let snapshot = metrics.snapshot(None);
assert_eq!(snapshot.backend_stats[0].total_commands.get(), 1);
}
#[test]
fn test_user_bytes_tracking() {
use crate::metrics::MetricsCollector;
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let metrics = MetricsCollector::new(1);
let session = ClientSession::builder(
addr.into(),
buffer_pool,
test_auth_handler(),
metrics.clone(),
)
.build();
session.set_username(Some("testuser".to_string()));
session.metrics.user_bytes_sent(session.username(), 1024);
session
.metrics
.user_bytes_received(session.username(), 2048);
let snapshot = metrics.snapshot(None);
let user_stats = snapshot
.user_stats
.iter()
.find(|s| s.username == "testuser");
assert!(user_stats.is_some());
let stats = user_stats.unwrap();
assert_eq!(stats.bytes_sent.as_u64(), 1024);
assert_eq!(stats.bytes_received.as_u64(), 2048);
}
#[test]
fn test_stateful_session_tracking() {
use crate::metrics::MetricsCollector;
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080);
let buffer_pool = BufferPool::new(BufferSize::try_new(1024).unwrap(), 4);
let metrics = MetricsCollector::new(1);
let session = ClientSession::builder(
addr.into(),
buffer_pool,
test_auth_handler(),
metrics.clone(),
)
.build();
session.metrics.stateful_session_started();
let snapshot = metrics.snapshot(None);
assert_eq!(snapshot.stateful_sessions, 1);
session.metrics.stateful_session_ended();
let snapshot = metrics.snapshot(None);
assert_eq!(snapshot.stateful_sessions, 0);
}
}