use std::future::Future; use std::net::SocketAddr; use tokio::net::TcpListener; use tokio::time::Duration; use tokio::{join, try_join}; use tokio_stream::wrappers::TcpListenerStream; use tokio_stream::{self as stream, StreamExt}; use tonic::transport::{Channel, Error, Server}; use tonic::{Response, Streaming}; use integration::pb::{test_client::TestClient, test_server::TestServer, Input}; use integration::Svc; #[tokio::test] async fn smoke_unary() { let (mut c1, mut c2, mut c3, mut c4) = spawn().await.expect("clients"); let (r1, r2, r3, r4) = try_join!( c1.unary_call(input()), c2.unary_call(input()), c3.unary_call(input()), c4.unary_call(input()), ) .expect("responses"); assert!(meta(&r1) == meta(&r2) && meta(&r2) == meta(&r3) && meta(&r3) == meta(&r4)); assert!(data(&r1) == data(&r2) && data(&r2) == data(&r3) && data(&r3) == data(&r4)); } #[tokio::test] async fn smoke_client_stream() { let (mut c1, mut c2, mut c3, mut c4) = spawn().await.expect("clients"); let input_stream = || stream::iter(vec![input(), input()]); let (r1, r2, r3, r4) = try_join!( c1.client_stream(input_stream()), c2.client_stream(input_stream()), c3.client_stream(input_stream()), c4.client_stream(input_stream()), ) .expect("responses"); assert!(meta(&r1) == meta(&r2) && meta(&r2) == meta(&r3) && meta(&r3) == meta(&r4)); assert!(data(&r1) == data(&r2) && data(&r2) == data(&r3) && data(&r3) == data(&r4)); } #[tokio::test] async fn smoke_server_stream() { let (mut c1, mut c2, mut c3, mut c4) = spawn().await.expect("clients"); let (r1, r2, r3, r4) = try_join!( c1.server_stream(input()), c2.server_stream(input()), c3.server_stream(input()), c4.server_stream(input()), ) .expect("responses"); assert!(meta(&r1) == meta(&r2) && meta(&r2) == meta(&r3) && meta(&r3) == meta(&r4)); let r1 = stream(r1).await; let r2 = stream(r2).await; let r3 = stream(r3).await; let r4 = stream(r4).await; assert!(r1 == r2 && r2 == r3 && r3 == r4); } #[tokio::test] async fn smoke_error() { let (mut c1, mut c2, mut c3, mut c4) = spawn().await.expect("clients"); let boom = Input { id: 1, desc: "boom".to_owned(), }; let (r1, r2, r3, r4) = join!( c1.unary_call(boom.clone()), c2.unary_call(boom.clone()), c3.unary_call(boom.clone()), c4.unary_call(boom.clone()), ); let s1 = r1.unwrap_err(); let s2 = r2.unwrap_err(); let s3 = r3.unwrap_err(); let s4 = r4.unwrap_err(); assert!(status(&s1) == status(&s2) && status(&s2) == status(&s3) && status(&s3) == status(&s4)) } async fn bind() -> (TcpListener, String) { let addr = SocketAddr::from(([127, 0, 0, 1], 0)); let lis = TcpListener::bind(addr).await.expect("listener"); let url = format!("http://{}", lis.local_addr().unwrap()); (lis, url) } async fn grpc(accept_h1: bool) -> (impl Future>, String) { let (listener, url) = bind().await; let fut = Server::builder() .accept_http1(accept_h1) .add_service(TestServer::new(Svc)) .serve_with_incoming(TcpListenerStream::new(listener)); (fut, url) } async fn grpc_web(accept_h1: bool) -> (impl Future>, String) { let (listener, url) = bind().await; let svc = tonic_web::config() .allow_origins(vec!["http://foo.com"]) .enable(TestServer::new(Svc)); let fut = Server::builder() .accept_http1(accept_h1) .add_service(svc) .serve_with_incoming(TcpListenerStream::new(listener)); (fut, url) } type Client = TestClient; async fn spawn() -> Result<(Client, Client, Client, Client), Error> { let ((s1, u1), (s2, u2), (s3, u3), (s4, u4)) = join!(grpc(true), grpc(false), grpc_web(true), grpc_web(false)); let _ = tokio::spawn(async move { join!(s1, s2, s3, s4) }); tokio::time::sleep(Duration::from_millis(30)).await; try_join!( TestClient::connect(u1), TestClient::connect(u2), TestClient::connect(u3), TestClient::connect(u4) ) } fn input() -> Input { Input { id: 1, desc: "one".to_owned(), } } fn meta(r: &Response) -> String { format!("{:?}", r.metadata()) } fn data(r: &Response) -> &T { r.get_ref() } async fn stream(r: Response>) -> Vec { r.into_inner().collect::, _>>().await.unwrap() } fn status(s: &tonic::Status) -> (String, tonic::Code) { (format!("{:?}", s.metadata()), s.code()) }