blob: d1ebb3cd076f829545daf9e4f7f544d16c64d470 [file] [log] [blame]
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -07001--
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
9--
10-- http://www.apache.org/licenses/LICENSE-2.0
11--
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
17-- under the License.
18--
19
20{-# LANGUAGE OverloadedStrings, RecordWildCards, ScopedTypeVariables #-}
21module Main where
22
23import Control.Exception
24import Control.Monad
25import Data.Functor
cdwijayarathnad9217912014-08-15 22:18:30 +053026import Data.List.Split
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070027import Data.String
28import Network
Jens Geyerd629ea02015-09-23 21:16:50 +020029import Network.URI
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070030import System.Environment
31import System.Exit
Jens Geyerd629ea02015-09-23 21:16:50 +020032import qualified Data.ByteString.Lazy as LBS
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070033import qualified Data.HashMap.Strict as Map
34import qualified Data.HashSet as Set
35import qualified Data.Vector as Vector
Jens Geyerd629ea02015-09-23 21:16:50 +020036import qualified System.IO as IO
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070037
38import ThriftTest_Iface
39import ThriftTest_Types
40import qualified ThriftTest_Client as Client
41
42import Thrift.Transport
Jens Geyerd629ea02015-09-23 21:16:50 +020043import Thrift.Transport.Framed
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070044import Thrift.Transport.Handle
Jens Geyerd629ea02015-09-23 21:16:50 +020045import Thrift.Transport.HttpClient
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070046import Thrift.Protocol
47import Thrift.Protocol.Binary
48import Thrift.Protocol.Compact
49import Thrift.Protocol.JSON
50
51data Options = Options
52 { host :: String
53 , port :: Int
54 , domainSocket :: String
55 , transport :: String
56 , protocol :: ProtocolType
Jens Geyerd629ea02015-09-23 21:16:50 +020057 -- TODO: Haskell lib does not have SSL support
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070058 , ssl :: Bool
59 , testLoops :: Int
60 }
61 deriving (Show, Eq)
62
Jens Geyerd629ea02015-09-23 21:16:50 +020063data TransportType = Buffered IO.Handle
64 | Framed (FramedTransport IO.Handle)
65 | Http HttpClient
66 | NoTransport String
67
68getTransport :: String -> String -> Int -> (IO TransportType)
69getTransport "buffered" host port = do
70 h <- hOpen (host, PortNumber $ fromIntegral port)
71 IO.hSetBuffering h $ IO.BlockBuffering Nothing
72 return $ Buffered h
73getTransport "framed" host port = do
74 h <- hOpen (host, PortNumber $ fromIntegral port)
75 t <- openFramedTransport h
76 return $ Framed t
77getTransport "http" host port = let uriStr = "http://" ++ host ++ ":" ++ show port in
78 case parseURI uriStr of
79 Nothing -> do return (NoTransport $ "Failed to parse URI: " ++ uriStr)
80 Just(uri) -> do
81 t <- openHttpClient uri
82 return $ Http t
83getTransport t host port = do return (NoTransport $ "Unsupported transport: " ++ t)
84
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070085data ProtocolType = Binary
86 | Compact
87 | JSON
88 deriving (Show, Eq)
89
90getProtocol :: String -> ProtocolType
91getProtocol "binary" = Binary
92getProtocol "compact" = Compact
93getProtocol "json" = JSON
94getProtocol p = error $ "Unsupported Protocol: " ++ p
95
96defaultOptions :: Options
97defaultOptions = Options
98 { port = 9090
99 , domainSocket = ""
100 , host = "localhost"
Jens Geyerd629ea02015-09-23 21:16:50 +0200101 , transport = "buffered"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700102 , protocol = Binary
103 , ssl = False
104 , testLoops = 1
105 }
106
107runClient :: (Protocol p, Transport t) => p t -> IO ()
108runClient p = do
109 let prot = (p,p)
110 putStrLn "Starting Tests"
cdwijayarathnad9217912014-08-15 22:18:30 +0530111
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700112 -- VOID Test
Jens Geyerd629ea02015-09-23 21:16:50 +0200113 putStrLn "testVoid"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700114 Client.testVoid prot
cdwijayarathnad9217912014-08-15 22:18:30 +0530115
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700116 -- String Test
Jens Geyerd629ea02015-09-23 21:16:50 +0200117 putStrLn "testString"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700118 s <- Client.testString prot "Test"
119 when (s /= "Test") exitFailure
120
Jens Geyerd629ea02015-09-23 21:16:50 +0200121 -- Bool Test
122 putStrLn "testBool"
123 bool <- Client.testBool prot True
124 when (not bool) exitFailure
125 putStrLn "testBool"
126 bool <- Client.testBool prot False
127 when (bool) exitFailure
128
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700129 -- Byte Test
Jens Geyerd629ea02015-09-23 21:16:50 +0200130 putStrLn "testByte"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700131 byte <- Client.testByte prot 1
132 when (byte /= 1) exitFailure
cdwijayarathnad9217912014-08-15 22:18:30 +0530133
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700134 -- I32 Test
Jens Geyerd629ea02015-09-23 21:16:50 +0200135 putStrLn "testI32"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700136 i32 <- Client.testI32 prot (-1)
137 when (i32 /= -1) exitFailure
cdwijayarathnad9217912014-08-15 22:18:30 +0530138
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700139 -- I64 Test
Jens Geyerd629ea02015-09-23 21:16:50 +0200140 putStrLn "testI64"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700141 i64 <- Client.testI64 prot (-34359738368)
142 when (i64 /= -34359738368) exitFailure
143
144 -- Double Test
Jens Geyerd629ea02015-09-23 21:16:50 +0200145 putStrLn "testDouble"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700146 dub <- Client.testDouble prot (-5.2098523)
147 when (abs (dub + 5.2098523) > 0.001) exitFailure
148
Jens Geyerd629ea02015-09-23 21:16:50 +0200149 -- Binary Test
150 putStrLn "testBinary"
151 bin <- Client.testBinary prot (LBS.pack . reverse $ [-128..127])
152 when ((reverse [-128..127]) /= LBS.unpack bin) exitFailure
Jens Geyer8bcfdd92014-12-14 03:14:26 +0100153
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700154 -- Struct Test
155 let structIn = Xtruct{ xtruct_string_thing = "Zero"
156 , xtruct_byte_thing = 1
157 , xtruct_i32_thing = -3
158 , xtruct_i64_thing = -5
159 }
Jens Geyerd629ea02015-09-23 21:16:50 +0200160 putStrLn "testStruct"
cdwijayarathnad9217912014-08-15 22:18:30 +0530161 structOut <- Client.testStruct prot structIn
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700162 when (structIn /= structOut) exitFailure
163
164 -- Nested Struct Test
165 let nestIn = Xtruct2{ xtruct2_byte_thing = 1
166 , xtruct2_struct_thing = structIn
167 , xtruct2_i32_thing = 5
168 }
Jens Geyerd629ea02015-09-23 21:16:50 +0200169 putStrLn "testNest"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700170 nestOut <- Client.testNest prot nestIn
Nobuaki Sukegawae68ccc22015-12-13 21:45:39 +0900171 when (nestIn /= nestOut) exitFailure
cdwijayarathnad9217912014-08-15 22:18:30 +0530172
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700173 -- Map Test
174 let mapIn = Map.fromList $ map (\i -> (i, i-10)) [1..5]
Jens Geyerd629ea02015-09-23 21:16:50 +0200175 putStrLn "testMap"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700176 mapOut <- Client.testMap prot mapIn
Nobuaki Sukegawae68ccc22015-12-13 21:45:39 +0900177 when (mapIn /= mapOut) exitFailure
cdwijayarathnad9217912014-08-15 22:18:30 +0530178
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700179 -- Set Test
180 let setIn = Set.fromList [-2..3]
Jens Geyerd629ea02015-09-23 21:16:50 +0200181 putStrLn "testSet"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700182 setOut <- Client.testSet prot setIn
183 when (setIn /= setOut) exitFailure
cdwijayarathnad9217912014-08-15 22:18:30 +0530184
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700185 -- List Test
186 let listIn = Vector.fromList [-2..3]
Jens Geyerd629ea02015-09-23 21:16:50 +0200187 putStrLn "testList"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700188 listOut <- Client.testList prot listIn
189 when (listIn /= listOut) exitFailure
cdwijayarathnad9217912014-08-15 22:18:30 +0530190
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700191 -- Enum Test
Jens Geyerd629ea02015-09-23 21:16:50 +0200192 putStrLn "testEnum"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700193 numz1 <- Client.testEnum prot ONE
194 when (numz1 /= ONE) exitFailure
195
Jens Geyerd629ea02015-09-23 21:16:50 +0200196 putStrLn "testEnum"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700197 numz2 <- Client.testEnum prot TWO
198 when (numz2 /= TWO) exitFailure
199
Jens Geyerd629ea02015-09-23 21:16:50 +0200200 putStrLn "testEnum"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700201 numz5 <- Client.testEnum prot FIVE
202 when (numz5 /= FIVE) exitFailure
203
204 -- Typedef Test
Jens Geyerd629ea02015-09-23 21:16:50 +0200205 putStrLn "testTypedef"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700206 uid <- Client.testTypedef prot 309858235082523
207 when (uid /= 309858235082523) exitFailure
cdwijayarathnad9217912014-08-15 22:18:30 +0530208
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700209 -- Nested Map Test
Jens Geyerd629ea02015-09-23 21:16:50 +0200210 putStrLn "testMapMap"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700211 _ <- Client.testMapMap prot 1
cdwijayarathnad9217912014-08-15 22:18:30 +0530212
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700213 -- Exception Test
Jens Geyerd629ea02015-09-23 21:16:50 +0200214 putStrLn "testException"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700215 exn1 <- try $ Client.testException prot "Xception"
216 case exn1 of
217 Left (Xception _ _) -> return ()
218 _ -> putStrLn (show exn1) >> exitFailure
cdwijayarathnad9217912014-08-15 22:18:30 +0530219
Jens Geyerd629ea02015-09-23 21:16:50 +0200220 putStrLn "testException"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700221 exn2 <- try $ Client.testException prot "TException"
222 case exn2 of
223 Left (_ :: SomeException) -> return ()
224 Right _ -> exitFailure
cdwijayarathnad9217912014-08-15 22:18:30 +0530225
Jens Geyerd629ea02015-09-23 21:16:50 +0200226 putStrLn "testException"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700227 exn3 <- try $ Client.testException prot "success"
228 case exn3 of
229 Left (_ :: SomeException) -> exitFailure
230 Right _ -> return ()
cdwijayarathnad9217912014-08-15 22:18:30 +0530231
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700232 -- Multi Exception Test
Jens Geyerd629ea02015-09-23 21:16:50 +0200233 putStrLn "testMultiException"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700234 multi1 <- try $ Client.testMultiException prot "Xception" "test 1"
235 case multi1 of
236 Left (Xception _ _) -> return ()
237 _ -> exitFailure
238
Jens Geyerd629ea02015-09-23 21:16:50 +0200239 putStrLn "testMultiException"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700240 multi2 <- try $ Client.testMultiException prot "Xception2" "test 2"
241 case multi2 of
242 Left (Xception2 _ _) -> return ()
243 _ -> exitFailure
244
Jens Geyerd629ea02015-09-23 21:16:50 +0200245 putStrLn "testMultiException"
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700246 multi3 <- try $ Client.testMultiException prot "success" "test 3"
247 case multi3 of
248 Left (_ :: SomeException) -> exitFailure
249 Right _ -> return ()
250
251
252main :: IO ()
253main = do
254 options <- flip parseFlags defaultOptions <$> getArgs
255 case options of
256 Nothing -> showHelp
257 Just Options{..} -> do
Jens Geyerd629ea02015-09-23 21:16:50 +0200258 trans <- Main.getTransport transport host port
259 case trans of
260 Buffered t -> runTest testLoops protocol t
261 Framed t -> runTest testLoops protocol t
262 Http t -> runTest testLoops protocol t
263 NoTransport err -> putStrLn err
264 where
265 makeClient p t = case p of
266 Binary -> runClient $ BinaryProtocol t
267 Compact -> runClient $ CompactProtocol t
268 JSON -> runClient $ JSONProtocol t
269 runTest loops p t = do
270 let client = makeClient p t
271 replicateM_ loops client
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700272 putStrLn "COMPLETED SUCCESSFULLY"
273
274parseFlags :: [String] -> Options -> Maybe Options
cdwijayarathnad9217912014-08-15 22:18:30 +0530275parseFlags (flag : flags) opts = do
276 let pieces = splitOn "=" flag
277 case pieces of
278 "--port" : arg : _ -> parseFlags flags opts{ port = read arg }
279 "--domain-socket" : arg : _ -> parseFlags flags opts{ domainSocket = read arg }
280 "--host" : arg : _ -> parseFlags flags opts{ host = arg }
281 "--transport" : arg : _ -> parseFlags flags opts{ transport = arg }
282 "--protocol" : arg : _ -> parseFlags flags opts{ protocol = getProtocol arg }
cdwijayarathna7191bc92014-08-16 23:36:07 +0530283 "-n" : arg : _ -> parseFlags flags opts{ testLoops = read arg }
cdwijayarathnad9217912014-08-15 22:18:30 +0530284 "--h" : _ -> Nothing
285 "--help" : _ -> Nothing
286 "--ssl" : _ -> parseFlags flags opts{ ssl = True }
287 "--processor-events" : _ -> parseFlags flags opts
cdwijayarathna7191bc92014-08-16 23:36:07 +0530288 _ -> Nothing
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700289parseFlags [] opts = Just opts
290
291showHelp :: IO ()
292showHelp = putStrLn
293 "Allowed options:\n\
294 \ -h [ --help ] produce help message\n\
295 \ --host arg (=localhost) Host to connect\n\
296 \ --port arg (=9090) Port number to connect\n\
cdwijayarathnad9217912014-08-15 22:18:30 +0530297 \ --domain-socket arg Domain Socket (e.g. /tmp/ThriftTest.thrift),\n\
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700298 \ instead of host and port\n\
Jens Geyerd629ea02015-09-23 21:16:50 +0200299 \ --transport arg (=buffered) Transport: buffered, framed, http\n\
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700300 \ --protocol arg (=binary) Protocol: binary, compact, json\n\
301 \ --ssl Encrypted Transport using SSL\n\
Jens Geyerd629ea02015-09-23 21:16:50 +0200302 \ -n [ --testloops ] arg (=1) Number of Tests"