#[cfg(feature = "grpc")]
pub use sz_orm_grpc::{
AuthInterceptor, GrpcChannel, GrpcError, GrpcMethod, GrpcServer, GrpcServerHandle,
GrpcServiceDef, GrpcStream, InMemoryUserService, Interceptor, InterceptorRequest,
LoggingInterceptor, RetryPolicy, RetryableErrorKind, TimeoutPolicy, UserGrpcClient,
UserGrpcService, UserRequest, UserResponse,
};
#[cfg(not(feature = "grpc"))]
compile_error!(
"gRPC facade requires the `grpc` feature. \
Enable it: sz-rust-orm-facade = { features = [\"grpc\"] }"
);
#[cfg(all(feature = "grpc", test))]
mod tests {
use super::*;
use std::sync::Arc;
fn unique_port() -> u16 {
51000 + (std::process::id() % 500) as u16
}
#[test]
fn test_grpc_facade_exports_server_and_service_def() {
let service = GrpcServiceDef {
name: "UserService".to_string(),
methods: vec![GrpcMethod {
name: "GetUser".to_string(),
input_type: "UserRequest".to_string(),
output_type: "UserResponse".to_string(),
client_streaming: false,
server_streaming: false,
}],
};
assert_eq!(service.name, "UserService");
assert_eq!(service.methods.len(), 1);
assert_eq!(service.methods[0].name, "GetUser");
}
#[test]
fn test_grpc_server_register_and_start() {
let port = unique_port();
let service = GrpcServiceDef {
name: "UserService".to_string(),
methods: vec![],
};
let server = GrpcServer::new("localhost", port).register_service(service);
let handle = server.start().expect("server should start");
assert!(handle.address().contains(&port.to_string()));
}
#[test]
fn test_grpc_server_start_no_services_fails() {
let server = GrpcServer::new("localhost", unique_port());
assert!(server.start().is_err());
}
#[test]
fn test_grpc_channel_new() {
let channel = GrpcChannel::new("localhost:50051");
assert_eq!(channel.address(), "localhost:50051");
}
#[test]
fn test_grpc_channel_with_metadata() {
let channel =
GrpcChannel::new("localhost:50051").with_metadata("authorization", "Bearer token123");
assert_eq!(
channel.metadata().get("authorization"),
Some(&"Bearer token123".to_string())
);
}
#[test]
fn test_user_grpc_client_connect_validates_empty_address() {
let result = UserGrpcClient::connect("");
assert!(result.is_err());
}
#[test]
fn test_logging_interceptor_always_ok() {
let interceptor = LoggingInterceptor;
let req = InterceptorRequest {
method: "GetUser".to_string(),
service_name: "UserService".to_string(),
metadata: std::collections::HashMap::new(),
};
assert!(interceptor.call(&req).is_ok());
}
#[test]
fn test_auth_interceptor_rejects_and_accepts() {
let interceptor = AuthInterceptor::new("Bearer secret");
let req = InterceptorRequest {
method: "GetUser".to_string(),
service_name: "UserService".to_string(),
metadata: std::collections::HashMap::new(),
};
assert!(matches!(
interceptor.call(&req),
Err(GrpcError::Unauthorized(_))
));
let mut metadata = std::collections::HashMap::new();
metadata.insert("authorization".to_string(), "Bearer secret".to_string());
let req = InterceptorRequest {
method: "GetUser".to_string(),
service_name: "UserService".to_string(),
metadata,
};
assert!(interceptor.call(&req).is_ok());
}
#[test]
fn test_retry_policy_default_values() {
let policy = RetryPolicy::default();
assert_eq!(policy.max_retries, 3);
assert_eq!(policy.initial_delay_ms, 50);
assert_eq!(policy.max_delay_ms, 1000);
assert_eq!(policy.multiplier, 2.0);
}
#[test]
fn test_timeout_policy_default() {
let policy = TimeoutPolicy::default();
assert_eq!(policy.deadline, std::time::Duration::from_secs(30));
}
#[test]
fn test_grpc_stream_basic() {
let stream = GrpcStream::new();
stream.push(1);
stream.push(2);
assert_eq!(stream.next(), Some(1));
assert_eq!(stream.next(), Some(2));
assert_eq!(stream.next(), None);
stream.close();
assert!(stream.is_closed());
}
#[test]
fn test_grpc_error_display() {
let err = GrpcError::ConnectionFailed("server down".to_string());
assert!(err.to_string().contains("Connection failed"));
}
#[test]
fn test_in_memory_user_service_crud() {
let svc = InMemoryUserService::new();
svc.add_user(UserResponse {
id: 1,
username: "alice".to_string(),
email: "alice@example.com".to_string(),
});
assert_eq!(svc.list_users().unwrap().len(), 1);
let user = svc
.get_user(UserRequest {
id: 1,
username: String::new(),
})
.unwrap();
assert_eq!(user.username, "alice");
assert!(svc.remove_user(1).is_some());
assert_eq!(svc.list_users().unwrap().len(), 0);
}
#[test]
fn test_grpc_end_to_end_client_server() {
let port = 52000u16 + (std::process::id() % 1000) as u16;
let addr = format!("localhost:{}", port);
let svc = Arc::new(InMemoryUserService::new().with_user(UserResponse {
id: 42,
username: "bob".to_string(),
email: "bob@example.com".to_string(),
}));
let server = GrpcServer::new("localhost", port)
.register_service(GrpcServiceDef {
name: "UserService".to_string(),
methods: vec![],
})
.register_user_service(svc);
let _handle = server.start().expect("server should start");
let client = UserGrpcClient::connect(&addr).expect("connect should succeed");
let user = client.get_user(42).expect("get_user should succeed");
assert_eq!(user.id, 42);
assert_eq!(user.username, "bob");
let missing = client.get_user(999);
assert!(missing.is_err());
}
}