1 use interop::client; 2 use std::{str::FromStr, time::Duration}; 3 use tonic::transport::Endpoint; 4 use tonic::transport::{Certificate, ClientTlsConfig}; 5 6 #[derive(Debug)] 7 struct Opts { 8 use_tls: bool, 9 test_case: Vec<Testcase>, 10 } 11 12 impl Opts { 13 fn parse() -> Result<Self, pico_args::Error> { 14 let mut pargs = pico_args::Arguments::from_env(); 15 Ok(Self { 16 use_tls: pargs.contains("--use_tls"), 17 test_case: pargs.value_from_fn("--test_case", |test_case| { 18 test_case.split(',').map(Testcase::from_str).collect() 19 })?, 20 }) 21 } 22 } 23 24 #[tokio::main] 25 async fn main() -> Result<(), Box<dyn std::error::Error>> { 26 interop::trace_init(); 27 28 let matches = Opts::parse()?; 29 30 let test_cases = matches.test_case; 31 32 #[allow(unused_mut)] 33 let mut endpoint = Endpoint::from_static("http://localhost:10000") 34 .timeout(Duration::from_secs(5)) 35 .concurrency_limit(30); 36 37 if matches.use_tls { 38 let pem = tokio::fs::read("interop/data/ca.pem").await?; 39 let ca = Certificate::from_pem(pem); 40 endpoint = endpoint.tls_config( 41 ClientTlsConfig::new() 42 .ca_certificate(ca) 43 .domain_name("foo.test.google.fr"), 44 )?; 45 } 46 47 let channel = endpoint.connect().await?; 48 49 let mut client = client::TestClient::new(channel.clone()); 50 let mut unimplemented_client = client::UnimplementedClient::new(channel); 51 52 let mut failures = Vec::new(); 53 54 for test_case in test_cases { 55 println!("{:?}:", test_case); 56 let mut test_results = Vec::new(); 57 58 match test_case { 59 Testcase::EmptyUnary => client::empty_unary(&mut client, &mut test_results).await, 60 Testcase::LargeUnary => client::large_unary(&mut client, &mut test_results).await, 61 Testcase::ClientStreaming => { 62 client::client_streaming(&mut client, &mut test_results).await 63 } 64 Testcase::ServerStreaming => { 65 client::server_streaming(&mut client, &mut test_results).await 66 } 67 Testcase::PingPong => client::ping_pong(&mut client, &mut test_results).await, 68 Testcase::EmptyStream => client::empty_stream(&mut client, &mut test_results).await, 69 Testcase::StatusCodeAndMessage => { 70 client::status_code_and_message(&mut client, &mut test_results).await 71 } 72 Testcase::SpecialStatusMessage => { 73 client::special_status_message(&mut client, &mut test_results).await 74 } 75 Testcase::UnimplementedMethod => { 76 client::unimplemented_method(&mut client, &mut test_results).await 77 } 78 Testcase::UnimplementedService => { 79 client::unimplemented_service(&mut unimplemented_client, &mut test_results).await 80 } 81 Testcase::CustomMetadata => { 82 client::custom_metadata(&mut client, &mut test_results).await 83 } 84 _ => unimplemented!(), 85 } 86 87 for result in test_results { 88 println!(" {}", result); 89 90 if result.is_failed() { 91 failures.push(result); 92 } 93 } 94 } 95 96 if !failures.is_empty() { 97 println!("{} tests failed", failures.len()); 98 std::process::exit(1); 99 } 100 101 Ok(()) 102 } 103 104 #[derive(Debug, strum::EnumString)] 105 #[strum(serialize_all = "snake_case")] 106 enum Testcase { 107 EmptyUnary, 108 CacheableUnary, 109 LargeUnary, 110 ClientCompressedUnary, 111 ServerCompressedUnary, 112 ClientStreaming, 113 ClientCompressedStreaming, 114 ServerStreaming, 115 ServerCompressedStreaming, 116 PingPong, 117 EmptyStream, 118 ComputeEngineCreds, 119 JwtTokenCreds, 120 Oauth2AuthToken, 121 PerRpcCreds, 122 CustomMetadata, 123 StatusCodeAndMessage, 124 SpecialStatusMessage, 125 UnimplementedMethod, 126 UnimplementedService, 127 CancelAfterBegin, 128 CancelAfterFirstResponse, 129 TimeoutOnSleepingServer, 130 ConcurrentLargeUnary, 131 } 132