summaryrefslogtreecommitdiffstats
path: root/src/jaegertracing/thrift/test/hs/TestClient.hs
blob: 93fb591b343a64c587b2cb411d5e1597d59233c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
--
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
--   http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.
--

{-# LANGUAGE OverloadedStrings, RecordWildCards, ScopedTypeVariables #-}
module Main where

import Control.Exception
import Control.Monad
import Data.Functor
import Data.List.Split
import Data.String
import Network
import Network.URI
import System.Environment
import System.Exit
import qualified Data.ByteString.Lazy as LBS
import qualified Data.HashMap.Strict as Map
import qualified Data.HashSet as Set
import qualified Data.Vector as Vector
import qualified System.IO as IO

import ThriftTest_Iface
import ThriftTest_Types
import qualified ThriftTest_Client as Client

import Thrift.Transport
import Thrift.Transport.Framed
import Thrift.Transport.Handle
import Thrift.Transport.HttpClient
import Thrift.Protocol
import Thrift.Protocol.Binary
import Thrift.Protocol.Compact
import Thrift.Protocol.Header
import Thrift.Protocol.JSON

data Options = Options
  { host         :: String
  , port         :: Int
  , domainSocket :: String
  , transport    :: String
  , protocol     :: ProtocolType
  -- TODO: Haskell lib does not have SSL support
  , ssl          :: Bool
  , testLoops    :: Int
  }
  deriving (Show, Eq)

data TransportType = Buffered IO.Handle
                   | Framed (FramedTransport IO.Handle)
                   | Http HttpClient
                   | NoTransport String

getTransport :: String -> String -> Int -> (IO TransportType)
getTransport "buffered" host port = do
  h <- hOpen (host, PortNumber $ fromIntegral port)
  IO.hSetBuffering h $ IO.BlockBuffering Nothing
  return $ Buffered h
getTransport "framed" host port = do
  h <- hOpen (host, PortNumber $ fromIntegral port)
  t <- openFramedTransport h
  return $ Framed t
getTransport "http" host port = let uriStr = "http://" ++ host ++ ":" ++ show port in
                                case parseURI uriStr of
                                  Nothing -> do return (NoTransport $ "Failed to parse URI: " ++ uriStr)
                                  Just(uri) -> do
                                    t <- openHttpClient uri
                                    return $ Http t
getTransport t host port = do return (NoTransport $ "Unsupported transport: " ++ t)

data ProtocolType = Binary
                  | Compact
                  | JSON
                  | Header
                  deriving (Show, Eq)

getProtocol :: String -> ProtocolType
getProtocol "binary"  = Binary
getProtocol "compact" = Compact
getProtocol "json"    = JSON
getProtocol "header" = Header
getProtocol p = error $ "Unsupported Protocol: " ++ p

defaultOptions :: Options
defaultOptions = Options
  { port         = 9090
  , domainSocket = ""
  , host         = "localhost"
  , transport    = "buffered"
  , protocol     = Binary
  , ssl          = False
  , testLoops    = 1
  }

runClient :: Protocol p => p -> IO ()
runClient p = do
  let prot = (p,p)
  putStrLn "Starting Tests"

  -- VOID Test
  putStrLn "testVoid"
  Client.testVoid prot

  -- String Test
  putStrLn "testString"
  s <- Client.testString prot "Test"
  when (s /= "Test") exitFailure

  -- Bool Test
  putStrLn "testBool"
  bool <- Client.testBool prot True
  when (not bool) exitFailure
  putStrLn "testBool"
  bool <- Client.testBool prot False
  when (bool) exitFailure

  -- Byte Test
  putStrLn "testByte"
  byte <- Client.testByte prot 1
  when (byte /= 1) exitFailure

  -- I32 Test
  putStrLn "testI32"
  i32 <- Client.testI32 prot (-1)
  when (i32 /= -1) exitFailure

  -- I64 Test
  putStrLn "testI64"
  i64 <- Client.testI64 prot (-34359738368)
  when (i64 /= -34359738368) exitFailure

  -- Double Test
  putStrLn "testDouble"
  dub <- Client.testDouble prot (-5.2098523)
  when (abs (dub + 5.2098523) > 0.001) exitFailure

  -- Binary Test
  putStrLn "testBinary"
  bin <- Client.testBinary prot (LBS.pack . reverse $ [-128..127])
  when ((reverse [-128..127]) /= LBS.unpack bin) exitFailure
  
  -- Struct Test
  let structIn = Xtruct{ xtruct_string_thing = "Zero"
                       , xtruct_byte_thing   = 1
                       , xtruct_i32_thing    = -3
                       , xtruct_i64_thing    = -5
                       }
  putStrLn "testStruct"
  structOut <- Client.testStruct prot structIn
  when (structIn /= structOut) exitFailure

  -- Nested Struct Test
  let nestIn = Xtruct2{ xtruct2_byte_thing   = 1
                      , xtruct2_struct_thing = structIn
                      , xtruct2_i32_thing    = 5
                      }
  putStrLn "testNest"
  nestOut <- Client.testNest prot nestIn
  when (nestIn /= nestOut) exitFailure

  -- Map Test
  let mapIn = Map.fromList $ map (\i -> (i, i-10)) [1..5]
  putStrLn "testMap"
  mapOut <- Client.testMap prot mapIn
  when (mapIn /= mapOut) exitFailure

  -- Set Test
  let setIn = Set.fromList [-2..3]
  putStrLn "testSet"
  setOut <- Client.testSet prot setIn
  when (setIn /= setOut) exitFailure

  -- List Test
  let listIn = Vector.fromList [-2..3]
  putStrLn "testList"
  listOut <- Client.testList prot listIn
  when (listIn /= listOut) exitFailure

  -- Enum Test
  putStrLn "testEnum"
  numz1 <- Client.testEnum prot ONE
  when (numz1 /= ONE) exitFailure

  putStrLn "testEnum"
  numz2 <- Client.testEnum prot TWO
  when (numz2 /= TWO) exitFailure

  putStrLn "testEnum"
  numz5 <- Client.testEnum prot FIVE
  when (numz5 /= FIVE) exitFailure

  -- Typedef Test
  putStrLn "testTypedef"
  uid <- Client.testTypedef prot 309858235082523
  when (uid /= 309858235082523) exitFailure

  -- Nested Map Test
  putStrLn "testMapMap"
  _ <- Client.testMapMap prot 1

  -- Exception Test
  putStrLn "testException"
  exn1 <- try $ Client.testException prot "Xception"
  case exn1 of
    Left (Xception _ _) -> return ()
    _ -> putStrLn (show exn1) >> exitFailure

  putStrLn "testException"
  exn2 <- try $ Client.testException prot "TException"
  case exn2 of
    Left (_ :: SomeException) -> return ()
    Right _ -> exitFailure

  putStrLn "testException"
  exn3 <- try $ Client.testException prot "success"
  case exn3 of
    Left (_ :: SomeException) -> exitFailure
    Right _ -> return ()

  -- Multi Exception Test
  putStrLn "testMultiException"
  multi1 <- try $ Client.testMultiException prot "Xception" "test 1"
  case multi1 of
    Left (Xception _ _) -> return ()
    _ -> exitFailure

  putStrLn "testMultiException"
  multi2 <- try $ Client.testMultiException prot "Xception2" "test 2"
  case multi2 of
    Left (Xception2 _ _) -> return ()
    _ -> exitFailure

  putStrLn "testMultiException"
  multi3 <- try $ Client.testMultiException prot "success" "test 3"
  case multi3 of
    Left (_ :: SomeException) -> exitFailure
    Right _ -> return ()


main :: IO ()
main = do
  options <- flip parseFlags defaultOptions <$> getArgs
  case options of
    Nothing -> showHelp
    Just Options{..} -> do
      trans <- Main.getTransport transport host port
      case trans of
        Buffered t -> runTest testLoops protocol t
        Framed t   -> runTest testLoops protocol t
        Http t     -> runTest testLoops protocol t
        NoTransport err -> putStrLn err
  where
    makeClient p t = case p of
                       Binary  -> runClient $ BinaryProtocol t
                       Compact -> runClient $ CompactProtocol t
                       JSON    -> runClient $ JSONProtocol t
                       Header  -> createHeaderProtocol t t >>= runClient
    runTest loops p t = do
      let client = makeClient p t
      replicateM_ loops client
      putStrLn "COMPLETED SUCCESSFULLY"

parseFlags :: [String] -> Options -> Maybe Options
parseFlags (flag : flags) opts = do
  let pieces = splitOn "=" flag
  case pieces of
    "--port" : arg : _ -> parseFlags flags opts{ port = read arg }
    "--domain-socket" : arg : _ -> parseFlags flags opts{ domainSocket = read arg }
    "--host" : arg : _ -> parseFlags flags opts{ host = arg }
    "--transport" : arg : _ -> parseFlags flags opts{ transport = arg }
    "--protocol" : arg : _ -> parseFlags flags opts{ protocol = getProtocol arg }
    "-n" : arg : _ -> parseFlags flags opts{ testLoops = read arg }
    "--h" : _ -> Nothing
    "--help" : _ -> Nothing
    "--ssl" : _ -> parseFlags flags opts{ ssl = True }
    "--processor-events" : _ -> parseFlags flags opts
    _ -> Nothing
parseFlags [] opts = Just opts

showHelp :: IO ()
showHelp = putStrLn
  "Allowed options:\n\
  \  -h [ --help ]               produce help message\n\
  \  --host arg (=localhost)     Host to connect\n\
  \  --port arg (=9090)          Port number to connect\n\
  \  --domain-socket arg         Domain Socket (e.g. /tmp/ThriftTest.thrift),\n\
  \                              instead of host and port\n\
  \  --transport arg (=buffered) Transport: buffered, framed, http\n\
  \  --protocol arg (=binary)    Protocol: binary, compact, json\n\
  \  --ssl                       Encrypted Transport using SSL\n\
  \  -n [ --testloops ] arg (=1) Number of Tests"