use folk_plugin_grpc::{GrpcConfig, GrpcEnvelope};
#[tokio::test]
async fn grpc_envelope_json_round_trip() {
let env = GrpcEnvelope {
service: "mypackage.MyService".into(),
method: "SayHello".into(),
payload: b"\x0a\x05world".to_vec(),
metadata: Default::default(),
};
let json = serde_json::to_string(&env).unwrap();
let decoded: GrpcEnvelope = serde_json::from_str(&json).unwrap();
assert_eq!(decoded.service, env.service);
assert_eq!(decoded.method, env.method);
assert_eq!(decoded.payload, env.payload);
assert!(decoded.metadata.is_empty());
}
#[tokio::test]
async fn grpc_envelope_payload_serializes_as_json_array() {
let env = GrpcEnvelope {
service: "test.Service".into(),
method: "DoThing".into(),
payload: vec![1, 2, 3],
metadata: Default::default(),
};
let value: serde_json::Value = serde_json::to_value(&env).unwrap();
let payload = value.get("payload").unwrap().as_array().unwrap();
assert_eq!(payload.len(), 3);
assert_eq!(payload[0], 1);
}
#[tokio::test]
async fn grpc_config_defaults() {
let config: GrpcConfig = serde_json::from_str("{}").unwrap();
assert_eq!(config.listen.to_string(), "0.0.0.0:50051");
assert!(config.proto.is_empty());
assert_eq!(config.max_recv_message_size, 4 * 1024 * 1024);
assert_eq!(config.max_send_message_size, 4 * 1024 * 1024);
assert!(config.timeout.is_none());
}
#[tokio::test]
async fn grpc_config_human_readable_sizes() {
let json = r#"{
"max_recv_message_size": "16mb",
"max_send_message_size": "8mb"
}"#;
let config: GrpcConfig = serde_json::from_str(json).unwrap();
assert_eq!(config.max_recv_message_size, 16 * 1024 * 1024);
assert_eq!(config.max_send_message_size, 8 * 1024 * 1024);
}
#[tokio::test]
async fn grpc_config_numeric_sizes() {
let json = r#"{
"max_recv_message_size": 1024,
"max_send_message_size": 2048
}"#;
let config: GrpcConfig = serde_json::from_str(json).unwrap();
assert_eq!(config.max_recv_message_size, 1024);
assert_eq!(config.max_send_message_size, 2048);
}
#[tokio::test]
async fn grpc_config_timeout() {
let json = r#"{"timeout": "30s"}"#;
let config: GrpcConfig = serde_json::from_str(json).unwrap();
assert_eq!(config.timeout, Some(std::time::Duration::from_secs(30)));
}
#[tokio::test]
async fn grpc_config_defaults_p1_fields() {
let config: GrpcConfig = serde_json::from_str("{}").unwrap();
assert!(config.max_concurrent_streams.is_none());
assert!(config.keepalive.is_none());
assert!(config.tls.is_none());
}
#[tokio::test]
async fn grpc_config_keepalive() {
let json = r#"{
"keepalive": {
"interval": "60s",
"timeout": "20s"
}
}"#;
let config: GrpcConfig = serde_json::from_str(json).unwrap();
let ka = config.keepalive.unwrap();
assert_eq!(ka.interval, std::time::Duration::from_secs(60));
assert_eq!(ka.timeout, std::time::Duration::from_secs(20));
}
#[tokio::test]
async fn grpc_config_tls() {
let json = r#"{
"tls": {
"cert": "/tmp/cert.pem",
"key": "/tmp/key.pem"
}
}"#;
let config: GrpcConfig = serde_json::from_str(json).unwrap();
let tls = config.tls.unwrap();
assert_eq!(tls.cert.to_str().unwrap(), "/tmp/cert.pem");
assert_eq!(tls.key.to_str().unwrap(), "/tmp/key.pem");
}
#[tokio::test]
async fn grpc_config_max_concurrent_streams() {
let json = r#"{"max_concurrent_streams": 200}"#;
let config: GrpcConfig = serde_json::from_str(json).unwrap();
assert_eq!(config.max_concurrent_streams, Some(200));
}
#[tokio::test]
async fn grpc_config_compression() {
let config: GrpcConfig = serde_json::from_str("{}").unwrap();
assert!(!config.compression);
let config: GrpcConfig = serde_json::from_str(r#"{"compression": true}"#).unwrap();
assert!(config.compression);
}
#[tokio::test]
async fn grpc_config_full_example() {
let json = r#"{
"listen": "0.0.0.0:9090",
"proto": ["proto/service.proto"],
"max_recv_message_size": "16mb",
"max_send_message_size": "8mb",
"timeout": "30s",
"max_concurrent_streams": 200,
"compression": true,
"keepalive": {"interval": "60s", "timeout": "20s"},
"tls": {"cert": "/etc/ssl/cert.pem", "key": "/etc/ssl/key.pem"}
}"#;
let config: GrpcConfig = serde_json::from_str(json).unwrap();
assert_eq!(config.listen.to_string(), "0.0.0.0:9090");
assert_eq!(config.proto, vec!["proto/service.proto"]);
assert_eq!(config.max_recv_message_size, 16 * 1024 * 1024);
assert_eq!(config.max_send_message_size, 8 * 1024 * 1024);
assert_eq!(config.timeout, Some(std::time::Duration::from_secs(30)));
assert_eq!(config.max_concurrent_streams, Some(200));
assert!(config.compression);
assert!(config.keepalive.is_some());
assert!(config.tls.is_some());
}
#[tokio::test]
async fn gzip_round_trip() {
use std::io::{Read as _, Write as _};
let original = b"hello gRPC compression test data";
let mut encoder = flate2::write::GzEncoder::new(Vec::new(), flate2::Compression::fast());
encoder.write_all(original).unwrap();
let compressed = encoder.finish().unwrap();
let mut decoder = flate2::read::GzDecoder::new(&compressed[..]);
let mut decompressed = Vec::new();
decoder.read_to_end(&mut decompressed).unwrap();
assert_eq!(decompressed, original);
}
#[tokio::test]
#[ignore = "requires php + protobuf extension + grpcurl"]
async fn grpc_plugin_handles_unary_call() {
todo!()
}