mirror of
https://github.com/cubixle/radius-rs.git
synced 2026-04-30 16:18:41 +01:00
Add E2E test
This commit is contained in:
@@ -8,4 +8,5 @@ members = [
|
|||||||
# Internal
|
# Internal
|
||||||
"code-generator",
|
"code-generator",
|
||||||
"examples",
|
"examples",
|
||||||
|
"e2e-test"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "e2e-test"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
license-file = "../LICENSE"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
radius = { version = "0.1.0", path = "../radius" }
|
||||||
|
radius-client = { version = "0.1.0", path = "../radius-client" }
|
||||||
|
radius-server = { version = "0.1.0", path = "../radius-server" }
|
||||||
|
tokio = { version = "0.3.4", features = ["signal", "net"] }
|
||||||
|
async-trait = "0.1.42"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
mod test;
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
use std::io;
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use tokio::net::UdpSocket;
|
||||||
|
use tokio::time::sleep;
|
||||||
|
|
||||||
|
use radius::code::Code;
|
||||||
|
use radius::request::Request;
|
||||||
|
use radius::rfc2865;
|
||||||
|
use radius_server::request_handler::RequestHandler;
|
||||||
|
use radius_server::secret_provider::{SecretProvider, SecretProviderError};
|
||||||
|
|
||||||
|
struct MyRequestHandler {}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl RequestHandler<(), io::Error> for MyRequestHandler {
|
||||||
|
async fn handle_radius_request(
|
||||||
|
&self,
|
||||||
|
conn: &UdpSocket,
|
||||||
|
req: &Request,
|
||||||
|
) -> Result<(), io::Error> {
|
||||||
|
let req_packet = req.get_packet();
|
||||||
|
let maybe_user_name_attr = rfc2865::lookup_user_name(req_packet);
|
||||||
|
let maybe_user_password_attr = rfc2865::lookup_user_password(req_packet);
|
||||||
|
|
||||||
|
let user_name = maybe_user_name_attr.unwrap().unwrap();
|
||||||
|
let user_password = String::from_utf8(maybe_user_password_attr.unwrap().unwrap()).unwrap();
|
||||||
|
let code = if user_name == "admin" && user_password == "p@ssw0rd" {
|
||||||
|
Code::AccessAccept
|
||||||
|
} else {
|
||||||
|
Code::AccessReject
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut resp_packet = req_packet.make_response_packet(code);
|
||||||
|
rfc2865::add_user_name(&mut resp_packet, user_name.as_str());
|
||||||
|
conn.send_to(&resp_packet.encode().unwrap(), req.get_remote_addr())
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LongTimeTakingHandler {}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl RequestHandler<(), io::Error> for LongTimeTakingHandler {
|
||||||
|
async fn handle_radius_request(
|
||||||
|
&self,
|
||||||
|
conn: &UdpSocket,
|
||||||
|
req: &Request,
|
||||||
|
) -> Result<(), io::Error> {
|
||||||
|
sleep(Duration::from_secs(30)).await;
|
||||||
|
let req_packet = req.get_packet();
|
||||||
|
let resp_packet = req_packet.make_response_packet(Code::AccessReject);
|
||||||
|
conn.send_to(&resp_packet.encode().unwrap(), req.get_remote_addr())
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MySecretProvider {}
|
||||||
|
|
||||||
|
impl SecretProvider for MySecretProvider {
|
||||||
|
fn fetch_secret(&self, _remote_addr: SocketAddr) -> Result<Vec<u8>, SecretProviderError> {
|
||||||
|
let bs = b"secret".to_vec();
|
||||||
|
Ok(bs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use tokio::sync::oneshot;
|
||||||
|
|
||||||
|
use radius::code::Code;
|
||||||
|
use radius::packet::Packet;
|
||||||
|
use radius::rfc2865;
|
||||||
|
use radius_client::client::{Client, ClientError};
|
||||||
|
use radius_server::server::Server;
|
||||||
|
|
||||||
|
use crate::test::{LongTimeTakingHandler, MyRequestHandler, MySecretProvider};
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_runner() {
|
||||||
|
test_access_request().await;
|
||||||
|
test_socket_timeout().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn test_access_request() {
|
||||||
|
let (sender, receiver) = oneshot::channel::<()>();
|
||||||
|
|
||||||
|
let port = 1812;
|
||||||
|
|
||||||
|
let server_proc = tokio::spawn(async move {
|
||||||
|
Server::run(
|
||||||
|
"0.0.0.0",
|
||||||
|
port,
|
||||||
|
1500,
|
||||||
|
true,
|
||||||
|
MyRequestHandler {},
|
||||||
|
MySecretProvider {},
|
||||||
|
receiver,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
let remote_addr: SocketAddr = format!("127.0.0.1:{}", port).parse().unwrap();
|
||||||
|
let client = Client::new(None, None);
|
||||||
|
|
||||||
|
let mut req_packet = Packet::new(Code::AccessRequest, &b"secret".to_vec());
|
||||||
|
rfc2865::add_user_name(&mut req_packet, "admin");
|
||||||
|
rfc2865::add_user_password(&mut req_packet, b"p@ssw0rd").unwrap();
|
||||||
|
let res = client.send_packet(&remote_addr, &req_packet).await.unwrap();
|
||||||
|
let maybe_user_name = rfc2865::lookup_user_name(&res);
|
||||||
|
let maybe_user_pass = rfc2865::lookup_user_password(&res);
|
||||||
|
assert_eq!(res.get_code(), Code::AccessAccept);
|
||||||
|
assert_eq!(maybe_user_name.is_some(), true);
|
||||||
|
assert_eq!(maybe_user_name.unwrap().unwrap(), "admin");
|
||||||
|
assert_eq!(maybe_user_pass.is_none(), true);
|
||||||
|
|
||||||
|
let mut req_packet = Packet::new(Code::AccessRequest, &b"secret".to_vec());
|
||||||
|
rfc2865::add_user_name(&mut req_packet, "admin");
|
||||||
|
rfc2865::add_user_password(&mut req_packet, b"INVALID-PASS").unwrap();
|
||||||
|
let res = client.send_packet(&remote_addr, &req_packet).await.unwrap();
|
||||||
|
assert_eq!(res.get_code(), Code::AccessReject);
|
||||||
|
|
||||||
|
sender.send(()).unwrap();
|
||||||
|
server_proc.await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn test_socket_timeout() {
|
||||||
|
let (sender, receiver) = oneshot::channel::<()>();
|
||||||
|
|
||||||
|
let port = 1812;
|
||||||
|
|
||||||
|
let server_proc = tokio::spawn(async move {
|
||||||
|
Server::run(
|
||||||
|
"0.0.0.0",
|
||||||
|
port,
|
||||||
|
1500,
|
||||||
|
true,
|
||||||
|
LongTimeTakingHandler {},
|
||||||
|
MySecretProvider {},
|
||||||
|
receiver,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
let remote_addr: SocketAddr = format!("127.0.0.1:{}", port).parse().unwrap();
|
||||||
|
let client = Client::new(None, Some(Duration::from_secs(0)));
|
||||||
|
|
||||||
|
let mut req_packet = Packet::new(Code::AccessRequest, &b"secret".to_vec());
|
||||||
|
rfc2865::add_user_name(&mut req_packet, "admin");
|
||||||
|
rfc2865::add_user_password(&mut req_packet, b"p@ssw0rd").unwrap();
|
||||||
|
let res = client.send_packet(&remote_addr, &req_packet).await;
|
||||||
|
assert_eq!(res.unwrap_err(), ClientError::SocketTimeoutError());
|
||||||
|
|
||||||
|
sender.send(()).unwrap();
|
||||||
|
server_proc.await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ use crate::client::ClientError::{
|
|||||||
FailedReceivingResponse, FailedSendingPacket, FailedUdpSocketBinding,
|
FailedReceivingResponse, FailedSendingPacket, FailedUdpSocketBinding,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, PartialEq, Debug)]
|
||||||
pub enum ClientError {
|
pub enum ClientError {
|
||||||
#[error("failed to bind a UDP socket => `{0}`")]
|
#[error("failed to bind a UDP socket => `{0}`")]
|
||||||
FailedUdpSocketBinding(String),
|
FailedUdpSocketBinding(String),
|
||||||
|
|||||||
Reference in New Issue
Block a user