| -- | 
 | -- 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 System.Environment | 
 | import System.Exit | 
 | import System.Posix.Unistd | 
 | import qualified Data.HashMap.Strict as Map | 
 | import qualified Data.HashSet as Set | 
 | import qualified Data.Vector as Vector | 
 |  | 
 | import ThriftTest_Iface | 
 | import ThriftTest_Types | 
 | import qualified ThriftTest_Client as Client | 
 |  | 
 | import Thrift.Transport | 
 | import Thrift.Transport.Handle | 
 | import Thrift.Protocol | 
 | import Thrift.Protocol.Binary | 
 | import Thrift.Protocol.Compact | 
 | import Thrift.Protocol.JSON | 
 |  | 
 | data Options = Options | 
 |   { host         :: String | 
 |   , port         :: Int | 
 |   , domainSocket :: String | 
 |   , transport    :: String | 
 |   , protocol     :: ProtocolType | 
 |   , ssl          :: Bool | 
 |   , testLoops    :: Int | 
 |   } | 
 |   deriving (Show, Eq) | 
 |  | 
 | data ProtocolType = Binary | 
 |                   | Compact | 
 |                   | JSON | 
 |                   deriving (Show, Eq) | 
 |  | 
 | getProtocol :: String -> ProtocolType | 
 | getProtocol "binary"  = Binary | 
 | getProtocol "compact" = Compact | 
 | getProtocol "json"    = JSON | 
 | getProtocol p = error $ "Unsupported Protocol: " ++ p | 
 |  | 
 | defaultOptions :: Options | 
 | defaultOptions = Options | 
 |   { port         = 9090 | 
 |   , domainSocket = "" | 
 |   , host         = "localhost" | 
 |   , transport    = "framed" | 
 |   , protocol     = Binary | 
 |   , ssl          = False | 
 |   , testLoops    = 1 | 
 |   } | 
 |  | 
 | runClient :: (Protocol p, Transport t) => p t -> IO () | 
 | runClient p = do | 
 |   let prot = (p,p) | 
 |   putStrLn "Starting Tests" | 
 |  | 
 |   -- VOID Test | 
 |   Client.testVoid prot | 
 |  | 
 |   -- String Test | 
 |   s <- Client.testString prot "Test" | 
 |   when (s /= "Test") exitFailure | 
 |  | 
 |   -- Byte Test | 
 |   byte <- Client.testByte prot 1 | 
 |   when (byte /= 1) exitFailure | 
 |  | 
 |   -- I32 Test | 
 |   i32 <- Client.testI32 prot (-1) | 
 |   when (i32 /= -1) exitFailure | 
 |  | 
 |   -- I64 Test | 
 |   i64 <- Client.testI64 prot (-34359738368) | 
 |   when (i64 /= -34359738368) exitFailure | 
 |  | 
 |   -- Double Test | 
 |   dub <- Client.testDouble prot (-5.2098523) | 
 |   when (abs (dub + 5.2098523) > 0.001) exitFailure | 
 |  | 
 |   -- Struct Test | 
 |   let structIn = Xtruct{ xtruct_string_thing = "Zero" | 
 |                        , xtruct_byte_thing   = 1 | 
 |                        , xtruct_i32_thing    = -3 | 
 |                        , xtruct_i64_thing    = -5 | 
 |                        } | 
 |   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 | 
 |                       } | 
 |   nestOut <- Client.testNest prot nestIn | 
 |   when (nestIn /= nestOut) exitSuccess | 
 |  | 
 |   -- Map Test | 
 |   let mapIn = Map.fromList $ map (\i -> (i, i-10)) [1..5] | 
 |   mapOut <- Client.testMap prot mapIn | 
 |   when (mapIn /= mapOut) exitSuccess | 
 |  | 
 |   -- Set Test | 
 |   let setIn = Set.fromList [-2..3] | 
 |   setOut <- Client.testSet prot setIn | 
 |   when (setIn /= setOut) exitFailure | 
 |  | 
 |   -- List Test | 
 |   let listIn = Vector.fromList [-2..3] | 
 |   listOut <- Client.testList prot listIn | 
 |   when (listIn /= listOut) exitFailure | 
 |  | 
 |   -- Enum Test | 
 |   numz1 <- Client.testEnum prot ONE | 
 |   when (numz1 /= ONE) exitFailure | 
 |  | 
 |   numz2 <- Client.testEnum prot TWO | 
 |   when (numz2 /= TWO) exitFailure | 
 |  | 
 |   numz5 <- Client.testEnum prot FIVE | 
 |   when (numz5 /= FIVE) exitFailure | 
 |  | 
 |   -- Typedef Test | 
 |   uid <- Client.testTypedef prot 309858235082523 | 
 |   when (uid /= 309858235082523) exitFailure | 
 |  | 
 |   -- Nested Map Test | 
 |   _ <- Client.testMapMap prot 1 | 
 |  | 
 |   -- Exception Test | 
 |   exn1 <- try $ Client.testException prot "Xception" | 
 |   case exn1 of | 
 |     Left (Xception _ _) -> return () | 
 |     _ -> putStrLn (show exn1) >> exitFailure | 
 |  | 
 |   exn2 <- try $ Client.testException prot "TException" | 
 |   case exn2 of | 
 |     Left (_ :: SomeException) -> return () | 
 |     Right _ -> exitFailure | 
 |  | 
 |   exn3 <- try $ Client.testException prot "success" | 
 |   case exn3 of | 
 |     Left (_ :: SomeException) -> exitFailure | 
 |     Right _ -> return () | 
 |  | 
 |   -- Multi Exception Test | 
 |   multi1 <- try $ Client.testMultiException prot "Xception" "test 1" | 
 |   case multi1 of | 
 |     Left (Xception _ _) -> return () | 
 |     _ -> exitFailure | 
 |  | 
 |   multi2 <- try $ Client.testMultiException prot "Xception2" "test 2" | 
 |   case multi2 of | 
 |     Left (Xception2 _ _) -> return () | 
 |     _ -> exitFailure | 
 |  | 
 |   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 | 
 |       handle <- hOpen (host, PortNumber $ fromIntegral port) | 
 |       let client = case protocol of | 
 |             Binary  -> runClient $ BinaryProtocol handle | 
 |             Compact -> runClient $ CompactProtocol handle | 
 |             JSON    -> runClient $ JSONProtocol handle | 
 |       replicateM_ testLoops 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, evhttp\n\ | 
 |   \  --protocol arg (=binary)    Protocol: binary, compact, json\n\ | 
 |   \  --ssl                       Encrypted Transport using SSL\n\ | 
 |   \  -n [ --testloops ] arg (=1) Number of Tests" |