THRIFT-4186 Add travis build for Rust
Client: rs
Patch: Allen George <allen.george@gmail.com>

This closes #1260
diff --git a/test/rs/Cargo.toml b/test/rs/Cargo.toml
index 8167390..df84504 100644
--- a/test/rs/Cargo.toml
+++ b/test/rs/Cargo.toml
@@ -7,6 +7,8 @@
 
 [dependencies]
 clap = "2.18.0"
+env_logger = "0.4.0"
+log = "0.3.7"
 ordered-float = "0.3.0"
 try_from = "0.2.0"
 
diff --git a/test/rs/src/bin/test_client.rs b/test/rs/src/bin/test_client.rs
index aad78a0..d720313 100644
--- a/test/rs/src/bin/test_client.rs
+++ b/test/rs/src/bin/test_client.rs
@@ -16,6 +16,10 @@
 // under the License.
 
 #[macro_use]
+extern crate log;
+extern crate env_logger;
+
+#[macro_use]
 extern crate clap;
 extern crate ordered_float;
 extern crate thrift;
@@ -26,17 +30,22 @@
 use std::fmt::Debug;
 
 use thrift::protocol::{TBinaryInputProtocol, TBinaryOutputProtocol, TCompactInputProtocol,
-                       TCompactOutputProtocol, TInputProtocol, TOutputProtocol};
+                       TCompactOutputProtocol, TInputProtocol, TMultiplexedOutputProtocol,
+                       TOutputProtocol};
 use thrift::transport::{ReadHalf, TBufferedReadTransport, TBufferedWriteTransport,
                         TFramedReadTransport, TFramedWriteTransport, TIoChannel, TReadTransport,
                         TTcpChannel, TWriteTransport, WriteHalf};
 use thrift_test::*;
 
 fn main() {
+    env_logger::init().expect("logger setup failed");
+
+    debug!("initialized logger - running cross-test client");
+
     match run() {
-        Ok(()) => println!("cross-test client succeeded"),
+        Ok(()) => info!("cross-test client succeeded"),
         Err(e) => {
-            println!("cross-test client failed with error {:?}", e);
+            info!("cross-test client failed with error {:?}", e);
             std::process::exit(1);
         }
     }
@@ -59,7 +68,7 @@
         (@arg protocol: --protocol +takes_value "Thrift protocol implementation to use (\"binary\", \"compact\")")
         (@arg testloops: -n --testloops +takes_value "Number of times to run tests")
     )
-            .get_matches();
+        .get_matches();
 
     let host = matches.value_of("host").unwrap_or("127.0.0.1");
     let port = value_t!(matches, "port", u16).unwrap_or(9090);
@@ -67,33 +76,20 @@
     let transport = matches.value_of("transport").unwrap_or("buffered");
     let protocol = matches.value_of("protocol").unwrap_or("binary");
 
-    let (i_chan, o_chan) = tcp_channel(host, port)?;
 
-    let (i_tran, o_tran) = match transport {
-        "buffered" => {
-            (Box::new(TBufferedReadTransport::new(i_chan)) as Box<TReadTransport>,
-             Box::new(TBufferedWriteTransport::new(o_chan)) as Box<TWriteTransport>)
-        }
-        "framed" => {
-            (Box::new(TFramedReadTransport::new(i_chan)) as Box<TReadTransport>,
-             Box::new(TFramedWriteTransport::new(o_chan)) as Box<TWriteTransport>)
-        }
-        unmatched => return Err(format!("unsupported transport {}", unmatched).into()),
+    let mut thrift_test_client = {
+        let (i_prot, o_prot) = build_protocols(host, port, transport, protocol, "ThriftTest")?;
+        ThriftTestSyncClient::new(i_prot, o_prot)
     };
 
-    let (i_prot, o_prot): (Box<TInputProtocol>, Box<TOutputProtocol>) = match protocol {
-        "binary" => {
-            (Box::new(TBinaryInputProtocol::new(i_tran, true)),
-             Box::new(TBinaryOutputProtocol::new(o_tran, true)))
-        }
-        "compact" => {
-            (Box::new(TCompactInputProtocol::new(i_tran)),
-             Box::new(TCompactOutputProtocol::new(o_tran)))
-        }
-        unmatched => return Err(format!("unsupported protocol {}", unmatched).into()),
+    let mut second_service_client = if protocol.starts_with("multi") {
+        let (i_prot, o_prot) = build_protocols(host, port, transport, protocol, "SecondService")?;
+        Some(SecondServiceSyncClient::new(i_prot, o_prot))
+    } else {
+        None
     };
 
-    println!(
+    info!(
         "connecting to {}:{} with {}+{} stack",
         host,
         port,
@@ -101,15 +97,62 @@
         transport
     );
 
-    let mut client = ThriftTestSyncClient::new(i_prot, o_prot);
-
     for _ in 0..testloops {
-        make_thrift_calls(&mut client)?
+        make_thrift_calls(&mut thrift_test_client, &mut second_service_client)?
     }
 
     Ok(())
 }
 
+fn build_protocols(
+    host: &str,
+    port: u16,
+    transport: &str,
+    protocol: &str,
+    service_name: &str,
+) -> thrift::Result<(Box<TInputProtocol>, Box<TOutputProtocol>)> {
+    let (i_chan, o_chan) = tcp_channel(host, port)?;
+
+    let (i_tran, o_tran): (Box<TReadTransport>, Box<TWriteTransport>) = match transport {
+        "buffered" => {
+            (Box::new(TBufferedReadTransport::new(i_chan)),
+             Box::new(TBufferedWriteTransport::new(o_chan)))
+        }
+        "framed" => {
+            (Box::new(TFramedReadTransport::new(i_chan)),
+             Box::new(TFramedWriteTransport::new(o_chan)))
+        }
+        unmatched => return Err(format!("unsupported transport {}", unmatched).into()),
+    };
+
+    let (i_prot, o_prot): (Box<TInputProtocol>, Box<TOutputProtocol>) = match protocol {
+        "binary" | "multi:binary" => {
+            (Box::new(TBinaryInputProtocol::new(i_tran, true)),
+             Box::new(TBinaryOutputProtocol::new(o_tran, true)))
+        }
+        "multi" => {
+            (Box::new(TBinaryInputProtocol::new(i_tran, true)),
+             Box::new(
+                TMultiplexedOutputProtocol::new(
+                    service_name,
+                    TBinaryOutputProtocol::new(o_tran, true),
+                ),
+            ))
+        }
+        "compact" | "multi:compact" => {
+            (Box::new(TCompactInputProtocol::new(i_tran)),
+             Box::new(TCompactOutputProtocol::new(o_tran)))
+        }
+        "multic" => {
+            (Box::new(TCompactInputProtocol::new(i_tran)),
+             Box::new(TMultiplexedOutputProtocol::new(service_name, TCompactOutputProtocol::new(o_tran)),))
+        }
+        unmatched => return Err(format!("unsupported protocol {}", unmatched).into()),
+    };
+
+    Ok((i_prot, o_prot))
+}
+
 // FIXME: expose "open" through the client interface so I don't have to early
 // open
 fn tcp_channel(
@@ -121,57 +164,69 @@
     c.split()
 }
 
-fn make_thrift_calls(client: &mut ThriftTestSyncClient<Box<TInputProtocol>, Box<TOutputProtocol>>,)
-    -> Result<(), thrift::Error> {
-    println!("testVoid");
-    client.test_void()?;
+type BuildThriftTestClient = ThriftTestSyncClient<Box<TInputProtocol>, Box<TOutputProtocol>>;
+type BuiltSecondServiceClient = SecondServiceSyncClient<Box<TInputProtocol>, Box<TOutputProtocol>>;
 
-    println!("testString");
-    verify_expected_result(client.test_string("thing".to_owned()), "thing".to_owned())?;
+#[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))]
+fn make_thrift_calls(
+    thrift_test_client: &mut BuildThriftTestClient,
+    second_service_client: &mut Option<BuiltSecondServiceClient>,
+) -> Result<(), thrift::Error> {
+    info!("testVoid");
+    thrift_test_client.test_void()?;
 
-    println!("testBool");
-    verify_expected_result(client.test_bool(true), true)?;
-
-    println!("testBool");
-    verify_expected_result(client.test_bool(false), false)?;
-
-    println!("testByte");
-    verify_expected_result(client.test_byte(42), 42)?;
-
-    println!("testi32");
-    verify_expected_result(client.test_i32(1159348374), 1159348374)?;
-
-    println!("testi64");
-    // try!(verify_expected_result(client.test_i64(-8651829879438294565),
-    // -8651829879438294565));
-    verify_expected_result(client.test_i64(i64::min_value()), i64::min_value())?;
-
-    println!("testDouble");
+    info!("testString");
     verify_expected_result(
-        client.test_double(OrderedFloat::from(42.42)),
+        thrift_test_client.test_string("thing".to_owned()),
+        "thing".to_owned(),
+    )?;
+
+    info!("testBool");
+    verify_expected_result(thrift_test_client.test_bool(true), true)?;
+
+    info!("testBool");
+    verify_expected_result(thrift_test_client.test_bool(false), false)?;
+
+    info!("testByte");
+    verify_expected_result(thrift_test_client.test_byte(42), 42)?;
+
+    info!("testi32");
+    verify_expected_result(thrift_test_client.test_i32(1159348374), 1159348374)?;
+
+    info!("testi64");
+    // try!(verify_expected_result(thrift_test_client.test_i64(-8651829879438294565),
+    // -8651829879438294565));
+    verify_expected_result(
+        thrift_test_client.test_i64(i64::min_value()),
+        i64::min_value(),
+    )?;
+
+    info!("testDouble");
+    verify_expected_result(
+        thrift_test_client.test_double(OrderedFloat::from(42.42)),
         OrderedFloat::from(42.42),
     )?;
 
-    println!("testTypedef");
+    info!("testTypedef");
     {
         let u_snd: UserId = 2348;
         let u_cmp: UserId = 2348;
-        verify_expected_result(client.test_typedef(u_snd), u_cmp)?;
+        verify_expected_result(thrift_test_client.test_typedef(u_snd), u_cmp)?;
     }
 
-    println!("testEnum");
+    info!("testEnum");
     {
-        verify_expected_result(client.test_enum(Numberz::TWO), Numberz::TWO)?;
+        verify_expected_result(thrift_test_client.test_enum(Numberz::TWO), Numberz::TWO)?;
     }
 
-    println!("testBinary");
+    info!("testBinary");
     {
         let b_snd = vec![0x77, 0x30, 0x30, 0x74, 0x21, 0x20, 0x52, 0x75, 0x73, 0x74];
         let b_cmp = vec![0x77, 0x30, 0x30, 0x74, 0x21, 0x20, 0x52, 0x75, 0x73, 0x74];
-        verify_expected_result(client.test_binary(b_snd), b_cmp)?;
+        verify_expected_result(thrift_test_client.test_binary(b_snd), b_cmp)?;
     }
 
-    println!("testStruct");
+    info!("testStruct");
     {
         let x_snd = Xtruct {
             string_thing: Some("foo".to_owned()),
@@ -185,7 +240,7 @@
             i32_thing: Some(219129),
             i64_thing: Some(12938492818),
         };
-        verify_expected_result(client.test_struct(x_snd), x_cmp)?;
+        verify_expected_result(thrift_test_client.test_struct(x_snd), x_cmp)?;
     }
 
     // Xtruct again, with optional values
@@ -197,12 +252,11 @@
     // let x_cmp = Xtruct { string_thing: Some("foo".to_owned()), byte_thing:
     // Some(0), i32_thing: Some(0), i64_thing: Some(12938492818) }; // the C++
     // server is responding correctly
-    // try!(verify_expected_result(client.test_struct(x_snd), x_cmp));
+    // try!(verify_expected_result(thrift_test_client.test_struct(x_snd), x_cmp));
     // }
     //
 
-
-    println!("testNest"); // (FIXME: try Xtruct2 with optional values)
+    info!("testNest"); // (FIXME: try Xtruct2 with optional values)
     {
         let x_snd = Xtruct2 {
             byte_thing: Some(32),
@@ -228,10 +282,33 @@
             ),
             i32_thing: Some(293481098),
         };
-        verify_expected_result(client.test_nest(x_snd), x_cmp)?;
+        verify_expected_result(thrift_test_client.test_nest(x_snd), x_cmp)?;
     }
 
-    println!("testList");
+    // do the multiplexed calls while making the main ThriftTest calls
+    if let Some(ref mut client) = second_service_client.as_mut() {
+        info!("SecondService blahBlah");
+        {
+            let r = client.blah_blah();
+            match r {
+                Err(thrift::Error::Application(ref e)) => {
+                    info!("received an {:?}", e);
+                    Ok(())
+                }
+                _ => Err(thrift::Error::User("did not get exception".into())),
+            }?;
+        }
+
+        info!("SecondService secondtestString");
+        {
+            verify_expected_result(
+                client.secondtest_string("test_string".to_owned()),
+                "testString(\"test_string\")".to_owned(),
+            )?;
+        }
+    }
+
+    info!("testList");
     {
         let mut v_snd: Vec<i32> = Vec::new();
         v_snd.push(29384);
@@ -243,10 +320,10 @@
         v_cmp.push(238);
         v_cmp.push(32498);
 
-        verify_expected_result(client.test_list(v_snd), v_cmp)?;
+        verify_expected_result(thrift_test_client.test_list(v_snd), v_cmp)?;
     }
 
-    println!("testSet");
+    info!("testSet");
     {
         let mut s_snd: BTreeSet<i32> = BTreeSet::new();
         s_snd.insert(293481);
@@ -258,10 +335,10 @@
         s_cmp.insert(23);
         s_cmp.insert(3234);
 
-        verify_expected_result(client.test_set(s_snd), s_cmp)?;
+        verify_expected_result(thrift_test_client.test_set(s_snd), s_cmp)?;
     }
 
-    println!("testMap");
+    info!("testMap");
     {
         let mut m_snd: BTreeMap<i32, i32> = BTreeMap::new();
         m_snd.insert(2, 4);
@@ -273,10 +350,10 @@
         m_cmp.insert(4, 6);
         m_cmp.insert(8, 7);
 
-        verify_expected_result(client.test_map(m_snd), m_cmp)?;
+        verify_expected_result(thrift_test_client.test_map(m_snd), m_cmp)?;
     }
 
-    println!("testStringMap");
+    info!("testStringMap");
     {
         let mut m_snd: BTreeMap<String, String> = BTreeMap::new();
         m_snd.insert("2".to_owned(), "4_string".to_owned());
@@ -288,13 +365,13 @@
         m_rcv.insert("4".to_owned(), "6_string".to_owned());
         m_rcv.insert("8".to_owned(), "7_string".to_owned());
 
-        verify_expected_result(client.test_string_map(m_snd), m_rcv)?;
+        verify_expected_result(thrift_test_client.test_string_map(m_snd), m_rcv)?;
     }
 
     // nested map
     // expect : {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2
     // => 2, 3 => 3, 4 => 4, }, }
-    println!("testMapMap");
+    info!("testMapMap");
     {
         let mut m_cmp_nested_0: BTreeMap<i32, i32> = BTreeMap::new();
         for i in (-4 as i32)..0 {
@@ -309,10 +386,10 @@
         m_cmp.insert(-4, m_cmp_nested_0);
         m_cmp.insert(4, m_cmp_nested_1);
 
-        verify_expected_result(client.test_map_map(42), m_cmp)?;
+        verify_expected_result(thrift_test_client.test_map_map(42), m_cmp)?;
     }
 
-    println!("testMulti");
+    info!("testMulti");
     {
         let mut m_snd: BTreeMap<i16, String> = BTreeMap::new();
         m_snd.insert(1298, "fizz".to_owned());
@@ -326,7 +403,7 @@
         };
 
         verify_expected_result(
-            client.test_multi(1, -123948, -19234123981, m_snd, Numberz::EIGHT, 81),
+            thrift_test_client.test_multi(1, -123948, -19234123981, m_snd, Numberz::EIGHT, 81),
             s_cmp,
         )?;
     }
@@ -388,12 +465,12 @@
         s_cmp.insert(1 as UserId, s_cmp_nested_1);
         s_cmp.insert(2 as UserId, s_cmp_nested_2);
 
-        verify_expected_result(client.test_insanity(insanity.clone()), s_cmp)?;
+        verify_expected_result(thrift_test_client.test_insanity(insanity.clone()), s_cmp)?;
     }
 
-    println!("testException - remote throws Xception");
+    info!("testException - remote throws Xception");
     {
-        let r = client.test_exception("Xception".to_owned());
+        let r = thrift_test_client.test_exception("Xception".to_owned());
         let x = match r {
             Err(thrift::Error::User(ref e)) => {
                 match e.downcast_ref::<Xception>() {
@@ -412,30 +489,31 @@
         verify_expected_result(Ok(x), &x_cmp)?;
     }
 
-    println!("testException - remote throws TApplicationException");
+    info!("testException - remote throws TApplicationException");
     {
-        let r = client.test_exception("TException".to_owned());
+        let r = thrift_test_client.test_exception("TException".to_owned());
         match r {
             Err(thrift::Error::Application(ref e)) => {
-                println!("received an {:?}", e);
+                info!("received an {:?}", e);
                 Ok(())
             }
             _ => Err(thrift::Error::User("did not get exception".into())),
         }?;
     }
 
-    println!("testException - remote succeeds");
+    info!("testException - remote succeeds");
     {
-        let r = client.test_exception("foo".to_owned());
+        let r = thrift_test_client.test_exception("foo".to_owned());
         match r {
             Ok(_) => Ok(()),
             _ => Err(thrift::Error::User("received an exception".into())),
         }?;
     }
 
-    println!("testMultiException - remote throws Xception");
+    info!("testMultiException - remote throws Xception");
     {
-        let r = client.test_multi_exception("Xception".to_owned(), "ignored".to_owned());
+        let r =
+            thrift_test_client.test_multi_exception("Xception".to_owned(), "ignored".to_owned());
         let x = match r {
             Err(thrift::Error::User(ref e)) => {
                 match e.downcast_ref::<Xception>() {
@@ -454,9 +532,10 @@
         verify_expected_result(Ok(x), &x_cmp)?;
     }
 
-    println!("testMultiException - remote throws Xception2");
+    info!("testMultiException - remote throws Xception2");
     {
-        let r = client.test_multi_exception("Xception2".to_owned(), "ignored".to_owned());
+        let r =
+            thrift_test_client.test_multi_exception("Xception2".to_owned(), "ignored".to_owned());
         let x = match r {
             Err(thrift::Error::User(ref e)) => {
                 match e.downcast_ref::<Xception2>() {
@@ -485,9 +564,9 @@
         verify_expected_result(Ok(x), &x_cmp)?;
     }
 
-    println!("testMultiException - remote succeeds");
+    info!("testMultiException - remote succeeds");
     {
-        let r = client.test_multi_exception("haha".to_owned(), "RETURNED".to_owned());
+        let r = thrift_test_client.test_multi_exception("haha".to_owned(), "RETURNED".to_owned());
         let x = match r {
             Err(e) => Err(thrift::Error::User(format!("received an unexpected exception {:?}", e).into(),),),
             _ => r,
@@ -506,14 +585,14 @@
         verify_expected_result(Ok(x), x_cmp)?;
     }
 
-    println!("testOneWay - remote sleeps for 1 second");
+    info!("testOneWay - remote sleeps for 1 second");
     {
-        client.test_oneway(1)?;
+        thrift_test_client.test_oneway(1)?;
     }
 
     // final test to verify that the connection is still writable after the one-way
     // call
-    client.test_void()
+    thrift_test_client.test_void()
 }
 
 #[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
diff --git a/test/rs/src/bin/test_server.rs b/test/rs/src/bin/test_server.rs
index 9c738ab..a32e938 100644
--- a/test/rs/src/bin/test_server.rs
+++ b/test/rs/src/bin/test_server.rs
@@ -16,6 +16,10 @@
 // under the License.
 
 #[macro_use]
+extern crate log;
+extern crate env_logger;
+
+#[macro_use]
 extern crate clap;
 extern crate ordered_float;
 extern crate thrift;
@@ -29,17 +33,21 @@
 use thrift::protocol::{TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory,
                        TCompactInputProtocolFactory, TCompactOutputProtocolFactory,
                        TInputProtocolFactory, TOutputProtocolFactory};
-use thrift::server::TServer;
+use thrift::server::{TMultiplexedProcessor, TServer};
 use thrift::transport::{TBufferedReadTransportFactory, TBufferedWriteTransportFactory,
                         TFramedReadTransportFactory, TFramedWriteTransportFactory,
                         TReadTransportFactory, TWriteTransportFactory};
 use thrift_test::*;
 
 fn main() {
+    env_logger::init().expect("logger setup failed");
+
+    debug!("initialized logger - running cross-test server");
+
     match run() {
-        Ok(()) => println!("cross-test server succeeded"),
+        Ok(()) => info!("cross-test server succeeded"),
         Err(e) => {
-            println!("cross-test server failed with error {:?}", e);
+            info!("cross-test server failed with error {:?}", e);
             std::process::exit(1);
         }
     }
@@ -70,7 +78,7 @@
     let workers = value_t!(matches, "workers", usize).unwrap_or(4);
     let listen_address = format!("127.0.0.1:{}", port);
 
-    println!("binding to {}", listen_address);
+    info!("binding to {}", listen_address);
 
     let (i_transport_factory, o_transport_factory): (Box<TReadTransportFactory>,
                                                      Box<TWriteTransportFactory>) =
@@ -91,11 +99,11 @@
     let (i_protocol_factory, o_protocol_factory): (Box<TInputProtocolFactory>,
                                                    Box<TOutputProtocolFactory>) =
         match &*protocol {
-            "binary" => {
+            "binary" | "multi" | "multi:binary" => {
                 (Box::new(TBinaryInputProtocolFactory::new()),
                  Box::new(TBinaryOutputProtocolFactory::new()))
             }
-            "compact" => {
+            "compact" | "multic" | "multi:compact" => {
                 (Box::new(TCompactInputProtocolFactory::new()),
                  Box::new(TCompactOutputProtocolFactory::new()))
             }
@@ -104,91 +112,100 @@
             }
         };
 
-    let processor = ThriftTestSyncProcessor::new(ThriftTestSyncHandlerImpl {});
+    let test_processor = ThriftTestSyncProcessor::new(ThriftTestSyncHandlerImpl {});
 
-    let mut server = match &*server_type {
-        "simple" => {
-            TServer::new(
-                i_transport_factory,
-                i_protocol_factory,
-                o_transport_factory,
-                o_protocol_factory,
-                processor,
-                1,
-            )
-        }
-        "thread-pool" => {
-            TServer::new(
-                i_transport_factory,
-                i_protocol_factory,
-                o_transport_factory,
-                o_protocol_factory,
-                processor,
-                workers,
-            )
-        }
-        unknown => {
-            return Err(format!("unsupported server type {}", unknown).into());
-        }
-    };
+    match &*server_type {
+        "simple" | "thread-pool" => {
+            if protocol == "multi" || protocol == "multic" {
+                let second_service_processor = SecondServiceSyncProcessor::new(SecondServiceSyncHandlerImpl {},);
 
-    server.listen(&listen_address)
+                let mut multiplexed_processor = TMultiplexedProcessor::new();
+                multiplexed_processor
+                    .register("ThriftTest", Box::new(test_processor), true)?;
+                multiplexed_processor
+                    .register("SecondService", Box::new(second_service_processor), false)?;
+
+                let mut server = TServer::new(
+                    i_transport_factory,
+                    i_protocol_factory,
+                    o_transport_factory,
+                    o_protocol_factory,
+                    multiplexed_processor,
+                    workers,
+                );
+
+                server.listen(&listen_address)
+            } else {
+                let mut server = TServer::new(
+                    i_transport_factory,
+                    i_protocol_factory,
+                    o_transport_factory,
+                    o_protocol_factory,
+                    test_processor,
+                    workers,
+                );
+
+                server.listen(&listen_address)
+            }
+        }
+        unknown => Err(format!("unsupported server type {}", unknown).into()),
+    }
 }
 
 struct ThriftTestSyncHandlerImpl;
 impl ThriftTestSyncHandler for ThriftTestSyncHandlerImpl {
     fn handle_test_void(&self) -> thrift::Result<()> {
-        println!("testVoid()");
+        info!("testVoid()");
         Ok(())
     }
 
     fn handle_test_string(&self, thing: String) -> thrift::Result<String> {
-        println!("testString({})", &thing);
+        info!("testString({})", &thing);
         Ok(thing)
     }
 
     fn handle_test_bool(&self, thing: bool) -> thrift::Result<bool> {
-        println!("testBool({})", thing);
+        info!("testBool({})", thing);
         Ok(thing)
     }
 
     fn handle_test_byte(&self, thing: i8) -> thrift::Result<i8> {
-        println!("testByte({})", thing);
+        info!("testByte({})", thing);
         Ok(thing)
     }
 
     fn handle_test_i32(&self, thing: i32) -> thrift::Result<i32> {
-        println!("testi32({})", thing);
+        info!("testi32({})", thing);
         Ok(thing)
     }
 
     fn handle_test_i64(&self, thing: i64) -> thrift::Result<i64> {
-        println!("testi64({})", thing);
+        info!("testi64({})", thing);
         Ok(thing)
     }
 
     fn handle_test_double(&self, thing: OrderedFloat<f64>) -> thrift::Result<OrderedFloat<f64>> {
-        println!("testDouble({})", thing);
+        info!("testDouble({})", thing);
         Ok(thing)
     }
 
     fn handle_test_binary(&self, thing: Vec<u8>) -> thrift::Result<Vec<u8>> {
-        println!("testBinary({:?})", thing);
+        info!("testBinary({:?})", thing);
         Ok(thing)
     }
 
     fn handle_test_struct(&self, thing: Xtruct) -> thrift::Result<Xtruct> {
-        println!("testStruct({:?})", thing);
+        info!("testStruct({:?})", thing);
         Ok(thing)
     }
 
     fn handle_test_nest(&self, thing: Xtruct2) -> thrift::Result<Xtruct2> {
-        println!("testNest({:?})", thing);
+        info!("testNest({:?})", thing);
         Ok(thing)
     }
 
     fn handle_test_map(&self, thing: BTreeMap<i32, i32>) -> thrift::Result<BTreeMap<i32, i32>> {
-        println!("testMap({:?})", thing);
+        info!("testMap({:?})", thing);
         Ok(thing)
     }
 
@@ -196,27 +213,27 @@
         &self,
         thing: BTreeMap<String, String>,
     ) -> thrift::Result<BTreeMap<String, String>> {
-        println!("testStringMap({:?})", thing);
+        info!("testStringMap({:?})", thing);
         Ok(thing)
     }
 
     fn handle_test_set(&self, thing: BTreeSet<i32>) -> thrift::Result<BTreeSet<i32>> {
-        println!("testSet({:?})", thing);
+        info!("testSet({:?})", thing);
         Ok(thing)
     }
 
     fn handle_test_list(&self, thing: Vec<i32>) -> thrift::Result<Vec<i32>> {
-        println!("testList({:?})", thing);
+        info!("testList({:?})", thing);
         Ok(thing)
     }
 
     fn handle_test_enum(&self, thing: Numberz) -> thrift::Result<Numberz> {
-        println!("testEnum({:?})", thing);
+        info!("testEnum({:?})", thing);
         Ok(thing)
     }
 
     fn handle_test_typedef(&self, thing: UserId) -> thrift::Result<UserId> {
-        println!("testTypedef({})", thing);
+        info!("testTypedef({})", thing);
         Ok(thing)
     }
 
@@ -224,7 +241,7 @@
     /// {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2 =>
     /// 2, 3 => 3, 4 => 4, }, }
     fn handle_test_map_map(&self, hello: i32) -> thrift::Result<BTreeMap<i32, BTreeMap<i32, i32>>> {
-        println!("testMapMap({})", hello);
+        info!("testMapMap({})", hello);
 
         let mut inner_map_0: BTreeMap<i32, i32> = BTreeMap::new();
         for i in -4..(0 as i32) {
@@ -254,7 +271,7 @@
         &self,
         argument: Insanity,
     ) -> thrift::Result<BTreeMap<UserId, BTreeMap<Numberz, Insanity>>> {
-        println!("testInsanity({:?})", argument);
+        info!("testInsanity({:?})", argument);
         let mut map_0: BTreeMap<Numberz, Insanity> = BTreeMap::new();
         map_0.insert(Numberz::TWO, argument.clone());
         map_0.insert(Numberz::THREE, argument.clone());
@@ -300,7 +317,7 @@
     /// else if arg == "TException" throw TException
     /// else do not throw anything
     fn handle_test_exception(&self, arg: String) -> thrift::Result<()> {
-        println!("testException({})", arg);
+        info!("testException({})", arg);
 
         match &*arg {
             "Xception" => {
@@ -370,3 +387,16 @@
         Ok(())
     }
 }
+
+struct SecondServiceSyncHandlerImpl;
+impl SecondServiceSyncHandler for SecondServiceSyncHandlerImpl {
+    fn handle_blah_blah(&self) -> thrift::Result<()> {
+        Err(thrift::new_application_error(thrift::ApplicationErrorKind::Unknown, "blahBlah"),)
+    }
+
+    fn handle_secondtest_string(&self, thing: String) -> thrift::Result<String> {
+        info!("testString({})", &thing);
+        let ret = format!("testString(\"{}\")", &thing);
+        Ok(ret)
+    }
+}