2 -- Licensed to the Apache Software Foundation (ASF) under one
3 -- or more contributor license agreements. See the NOTICE file
4 -- distributed with this work for additional information
5 -- regarding copyright ownership. The ASF licenses this file
6 -- to you under the Apache License, Version 2.0 (the
7 -- "License"); you may not use this file except in compliance
8 -- with the License. You may obtain a copy of the License at
10 -- http://www.apache.org/licenses/LICENSE-2.0
12 -- Unless required by applicable law or agreed to in writing,
13 -- software distributed under the License is distributed on an
14 -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 -- KIND, either express or implied. See the License for the
16 -- specific language governing permissions and limitations
20 {-# LANGUAGE OverloadedStrings, RecordWildCards, ScopedTypeVariables #-}
23 import Control.Exception
26 import Data.List.Split
30 import System.Environment
32 import qualified Data.ByteString.Lazy as LBS
33 import qualified Data.HashMap.Strict as Map
34 import qualified Data.HashSet as Set
35 import qualified Data.Vector as Vector
36 import qualified System.IO as IO
38 import ThriftTest_Iface
39 import ThriftTest_Types
40 import qualified ThriftTest_Client as Client
42 import Thrift.Transport
43 import Thrift.Transport.Framed
44 import Thrift.Transport.Handle
45 import Thrift.Transport.HttpClient
46 import Thrift.Protocol
47 import Thrift.Protocol.Binary
48 import Thrift.Protocol.Compact
49 import Thrift.Protocol.Header
50 import Thrift.Protocol.JSON
52 data Options = Options
55 , domainSocket :: String
57 , protocol :: ProtocolType
58 -- TODO: Haskell lib does not have SSL support
64 data TransportType = Buffered IO.Handle
65 | Framed (FramedTransport IO.Handle)
69 getTransport :: String -> String -> Int -> (IO TransportType)
70 getTransport "buffered" host port = do
71 h <- hOpen (host, PortNumber $ fromIntegral port)
72 IO.hSetBuffering h $ IO.BlockBuffering Nothing
74 getTransport "framed" host port = do
75 h <- hOpen (host, PortNumber $ fromIntegral port)
76 t <- openFramedTransport h
78 getTransport "http" host port = let uriStr = "http://" ++ host ++ ":" ++ show port in
79 case parseURI uriStr of
80 Nothing -> do return (NoTransport $ "Failed to parse URI: " ++ uriStr)
82 t <- openHttpClient uri
84 getTransport t host port = do return (NoTransport $ "Unsupported transport: " ++ t)
86 data ProtocolType = Binary
92 getProtocol :: String -> ProtocolType
93 getProtocol "binary" = Binary
94 getProtocol "compact" = Compact
95 getProtocol "json" = JSON
96 getProtocol "header" = Header
97 getProtocol p = error $ "Unsupported Protocol: " ++ p
99 defaultOptions :: Options
100 defaultOptions = Options
104 , transport = "buffered"
110 runClient :: Protocol p => p -> IO ()
113 putStrLn "Starting Tests"
120 putStrLn "testString"
121 s <- Client.testString prot "Test"
122 when (s /= "Test") exitFailure
126 bool <- Client.testBool prot True
127 when (not bool) exitFailure
129 bool <- Client.testBool prot False
130 when (bool) exitFailure
134 byte <- Client.testByte prot 1
135 when (byte /= 1) exitFailure
139 i32 <- Client.testI32 prot (-1)
140 when (i32 /= -1) exitFailure
144 i64 <- Client.testI64 prot (-34359738368)
145 when (i64 /= -34359738368) exitFailure
148 putStrLn "testDouble"
149 dub <- Client.testDouble prot (-5.2098523)
150 when (abs (dub + 5.2098523) > 0.001) exitFailure
153 putStrLn "testBinary"
154 bin <- Client.testBinary prot (LBS.pack . reverse $ [-128..127])
155 when ((reverse [-128..127]) /= LBS.unpack bin) exitFailure
158 let structIn = Xtruct{ xtruct_string_thing = "Zero"
159 , xtruct_byte_thing = 1
160 , xtruct_i32_thing = -3
161 , xtruct_i64_thing = -5
163 putStrLn "testStruct"
164 structOut <- Client.testStruct prot structIn
165 when (structIn /= structOut) exitFailure
167 -- Nested Struct Test
168 let nestIn = Xtruct2{ xtruct2_byte_thing = 1
169 , xtruct2_struct_thing = structIn
170 , xtruct2_i32_thing = 5
173 nestOut <- Client.testNest prot nestIn
174 when (nestIn /= nestOut) exitFailure
177 let mapIn = Map.fromList $ map (\i -> (i, i-10)) [1..5]
179 mapOut <- Client.testMap prot mapIn
180 when (mapIn /= mapOut) exitFailure
183 let setIn = Set.fromList [-2..3]
185 setOut <- Client.testSet prot setIn
186 when (setIn /= setOut) exitFailure
189 let listIn = Vector.fromList [-2..3]
191 listOut <- Client.testList prot listIn
192 when (listIn /= listOut) exitFailure
196 numz1 <- Client.testEnum prot ONE
197 when (numz1 /= ONE) exitFailure
200 numz2 <- Client.testEnum prot TWO
201 when (numz2 /= TWO) exitFailure
204 numz5 <- Client.testEnum prot FIVE
205 when (numz5 /= FIVE) exitFailure
208 putStrLn "testTypedef"
209 uid <- Client.testTypedef prot 309858235082523
210 when (uid /= 309858235082523) exitFailure
213 putStrLn "testMapMap"
214 _ <- Client.testMapMap prot 1
217 putStrLn "testException"
218 exn1 <- try $ Client.testException prot "Xception"
220 Left (Xception _ _) -> return ()
221 _ -> putStrLn (show exn1) >> exitFailure
223 putStrLn "testException"
224 exn2 <- try $ Client.testException prot "TException"
226 Left (_ :: SomeException) -> return ()
227 Right _ -> exitFailure
229 putStrLn "testException"
230 exn3 <- try $ Client.testException prot "success"
232 Left (_ :: SomeException) -> exitFailure
235 -- Multi Exception Test
236 putStrLn "testMultiException"
237 multi1 <- try $ Client.testMultiException prot "Xception" "test 1"
239 Left (Xception _ _) -> return ()
242 putStrLn "testMultiException"
243 multi2 <- try $ Client.testMultiException prot "Xception2" "test 2"
245 Left (Xception2 _ _) -> return ()
248 putStrLn "testMultiException"
249 multi3 <- try $ Client.testMultiException prot "success" "test 3"
251 Left (_ :: SomeException) -> exitFailure
257 options <- flip parseFlags defaultOptions <$> getArgs
260 Just Options{..} -> do
261 trans <- Main.getTransport transport host port
263 Buffered t -> runTest testLoops protocol t
264 Framed t -> runTest testLoops protocol t
265 Http t -> runTest testLoops protocol t
266 NoTransport err -> putStrLn err
268 makeClient p t = case p of
269 Binary -> runClient $ BinaryProtocol t
270 Compact -> runClient $ CompactProtocol t
271 JSON -> runClient $ JSONProtocol t
272 Header -> createHeaderProtocol t t >>= runClient
273 runTest loops p t = do
274 let client = makeClient p t
275 replicateM_ loops client
276 putStrLn "COMPLETED SUCCESSFULLY"
278 parseFlags :: [String] -> Options -> Maybe Options
279 parseFlags (flag : flags) opts = do
280 let pieces = splitOn "=" flag
282 "--port" : arg : _ -> parseFlags flags opts{ port = read arg }
283 "--domain-socket" : arg : _ -> parseFlags flags opts{ domainSocket = read arg }
284 "--host" : arg : _ -> parseFlags flags opts{ host = arg }
285 "--transport" : arg : _ -> parseFlags flags opts{ transport = arg }
286 "--protocol" : arg : _ -> parseFlags flags opts{ protocol = getProtocol arg }
287 "-n" : arg : _ -> parseFlags flags opts{ testLoops = read arg }
289 "--help" : _ -> Nothing
290 "--ssl" : _ -> parseFlags flags opts{ ssl = True }
291 "--processor-events" : _ -> parseFlags flags opts
293 parseFlags [] opts = Just opts
298 \ -h [ --help ] produce help message\n\
299 \ --host arg (=localhost) Host to connect\n\
300 \ --port arg (=9090) Port number to connect\n\
301 \ --domain-socket arg Domain Socket (e.g. /tmp/ThriftTest.thrift),\n\
302 \ instead of host and port\n\
303 \ --transport arg (=buffered) Transport: buffered, framed, http\n\
304 \ --protocol arg (=binary) Protocol: binary, compact, json\n\
305 \ --ssl Encrypted Transport using SSL\n\
306 \ -n [ --testloops ] arg (=1) Number of Tests"