You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
6.1 KiB
169 lines
6.1 KiB
|
12 years ago
|
{-# LANGUAGE OverloadedStrings #-}
|
||
|
|
{-# LANGUAGE TemplateHaskell #-}
|
||
|
|
|
||
|
|
module Tests.Echo where
|
||
|
|
|
||
|
|
import Control.Concurrent.Async
|
||
|
|
import Control.Concurrent.STM
|
||
|
|
import Control.Lens
|
||
|
|
import Control.Monad
|
||
|
|
import Control.Monad.IO.Class
|
||
|
|
import Control.Monad.Trans.Maybe
|
||
|
|
import qualified Data.Text as Text
|
||
|
|
import Data.XML.Pickle
|
||
|
|
import Data.XML.Types
|
||
|
|
import Network.Xmpp
|
||
|
|
import Network.Xmpp.Marshal (pickleElem, unpickleElem)
|
||
|
|
import System.Log.Logger
|
||
|
|
import System.Timeout
|
||
|
|
import Test.Hspec
|
||
|
|
import Tests.Common
|
||
|
|
|
||
|
|
testNS :: Text.Text
|
||
|
|
testNS = "xmpp:library:test"
|
||
|
|
|
||
|
|
testName :: Text.Text -> Name
|
||
|
|
testName name = Name name (Just testNS) Nothing
|
||
|
|
|
||
|
|
data Payload = Payload
|
||
|
|
{ _payloadWantError :: Bool
|
||
|
|
, _payloadWantTimeout :: Bool
|
||
|
|
, _payloadText :: Text.Text
|
||
|
|
} deriving (Eq, Show)
|
||
|
|
|
||
|
|
makeLenses ''Payload
|
||
|
|
|
||
|
|
defaultPL :: Payload
|
||
|
|
defaultPL = Payload False False "ping"
|
||
|
|
|
||
|
|
-- | Automatically accept all subscription requests from other entities
|
||
|
|
autoAccept :: Session -> IO ()
|
||
|
|
autoAccept sess = forever $ do
|
||
|
|
st <- waitForPresence ((== Subscribe ) . presenceType ) sess
|
||
|
|
case presenceFrom st of
|
||
|
|
Just fr -> do
|
||
|
|
_ <- sendPresence (presenceSubscribed fr) sess
|
||
|
|
return ()
|
||
|
|
Nothing -> return () -- this shouldn't happen
|
||
|
|
|
||
|
|
payloadP :: PU [Node] Payload
|
||
|
|
payloadP = xpWrap (\((err, tout) , msg) -> Payload err tout msg)
|
||
|
|
(\(Payload err tout msg) ->
|
||
|
|
((err, tout) , msg)) $
|
||
|
|
xpElem (Name "request" (Just testNS) Nothing)
|
||
|
|
(xp2Tuple
|
||
|
|
(xpAttr "want-error" xpPrim)
|
||
|
|
(xpAttr "want-timeout" xpPrim)
|
||
|
|
)
|
||
|
|
(xpElemNodes (Name "message" (Just testNS) Nothing)
|
||
|
|
(xpContent xpId))
|
||
|
|
|
||
|
|
iqResponder :: Session -> IO b
|
||
|
|
iqResponder sess = do
|
||
|
|
chan' <- listenIQChan Set testNS sess
|
||
|
|
chan <- case chan' of
|
||
|
|
Left _ -> assertionFailed "Channel was already taken"
|
||
|
|
Right c -> return c
|
||
|
|
forever . void . runMaybeT $ do
|
||
|
|
next <- liftIO . atomically $ readTChan chan
|
||
|
|
let Right pld = unpickleElem payloadP . iqRequestPayload $
|
||
|
|
iqRequestBody next
|
||
|
|
when (pld^.payloadWantTimeout) mzero
|
||
|
|
let answerPayload = Payload False False (Text.reverse $ pld^.payloadText)
|
||
|
|
let answerBody = pickleElem payloadP answerPayload
|
||
|
|
let answer = case pld^.payloadWantError of
|
||
|
|
True -> Left $ mkStanzaError UndefinedCondition
|
||
|
|
False -> Right $ Just answerBody
|
||
|
|
liftIO $ answerIQ next answer
|
||
|
|
|
||
|
|
mirror :: Session -> IO b
|
||
|
|
mirror sess = forever $ do
|
||
|
|
msg <- getMessage sess
|
||
|
|
case (answerMessage msg (view payload msg)) of
|
||
|
|
Nothing -> return ()
|
||
|
|
Just answer -> void $ sendMessage answer sess
|
||
|
|
|
||
|
|
resp :: Session -> IO b
|
||
|
|
resp sess =
|
||
|
|
withAsync (iqResponder sess) $ \_ ->
|
||
|
|
mirror sess
|
||
|
|
|
||
|
|
|
||
|
|
---------------------------------------
|
||
|
|
-- Tests ------------------------------
|
||
|
|
---------------------------------------
|
||
|
|
|
||
|
|
test_messagePing :: Session -> IO ()
|
||
|
|
test_messagePing sess = do
|
||
|
|
infoM "Pontarius.Xmpp.Tests" "RUNNING message ping test"
|
||
|
|
let el = [Element (testName "ping") [] []]
|
||
|
|
_ <- sendMessage (message{ messagePayload = el
|
||
|
|
, messageTo = Just responder
|
||
|
|
}) sess
|
||
|
|
mbMessage <- timeout timeoutDuration (getMessage sess)
|
||
|
|
case mbMessage of
|
||
|
|
Nothing -> assertionFailed $ "ping: No answer within "
|
||
|
|
++ show (timeoutDuration `div` 1000000 :: Integer) ++ "seconds"
|
||
|
|
Just msg -> view payload msg `shouldBe` el
|
||
|
|
infoM "Pontarius.Xmpp.Tests" "SUCCESS message ping test"
|
||
|
|
|
||
|
|
test_IQ :: Payload
|
||
|
|
-> Session
|
||
|
|
-> IO (Either IQSendError IQResponse)
|
||
|
|
test_IQ pl sess = do
|
||
|
|
let el = pickleElem payloadP pl
|
||
|
|
sendIQ' (Just timeoutDuration) (Just responder) Set Nothing el sess
|
||
|
|
|
||
|
|
test_IQPing :: Session -> IO ()
|
||
|
|
test_IQPing sess = do
|
||
|
|
infoM "Pontarius.Xmpp.Tests" "RUNNING IQ ping test"
|
||
|
|
response <- test_IQ defaultPL sess
|
||
|
|
case response of
|
||
|
|
Left e -> assertionFailed $ "test_IQPing: " ++ show e
|
||
|
|
Right (IQResponseError e) -> assertionFailed $ "iqPing: " ++ show e
|
||
|
|
Right (IQResponseResult r) -> do
|
||
|
|
case view payload r of
|
||
|
|
Nothing -> assertionFailed "test_IQPing: no payload"
|
||
|
|
Just pl' -> case unpickleElem payloadP pl' of
|
||
|
|
Left e -> assertionFailed $ "test_IQPing: unpickling\
|
||
|
|
\returned unpickleError" ++ show e
|
||
|
|
Right pl -> pl `shouldBe` Payload False False "gnip"
|
||
|
|
infoM "Pontarius.Xmpp.Tests" "SUCCESS IQ ping test"
|
||
|
|
|
||
|
|
test_IQError :: Session -> IO ()
|
||
|
|
test_IQError sess = do
|
||
|
|
infoM "Pontarius.Xmpp.Tests" "RUNNING IQ Error test"
|
||
|
|
response <- test_IQ (defaultPL & payloadWantError .~ True) sess
|
||
|
|
case response of
|
||
|
|
Left e -> assertionFailed $ "iqPing: " ++ show e
|
||
|
|
Right (IQResponseError e) -> e^.stanzaError.stanzaErrorConditionL
|
||
|
|
`shouldBe` UndefinedCondition
|
||
|
|
Right (IQResponseResult r) -> assertionFailed $ "test_IQError:\
|
||
|
|
\Expected IQ error but got" ++ show r
|
||
|
|
infoM "Pontarius.Xmpp.Tests" "SUCCESS IQ Error test"
|
||
|
|
|
||
|
|
test_IQTimeout :: Session -> IO ()
|
||
|
|
test_IQTimeout sess = do
|
||
|
|
infoM "Pontarius.Xmpp.Tests" "RUNNING IQ Timeout test"
|
||
|
|
response <- test_IQ (defaultPL & payloadWantTimeout .~ True) sess
|
||
|
|
case response of
|
||
|
|
Left IQTimeOut -> return ()
|
||
|
|
err -> assertionFailed $ "test_IQTimeout: Expected timeout but got"
|
||
|
|
++ show err
|
||
|
|
infoM "Pontarius.Xmpp.Tests" "SUCCESS IQ Timeout test"
|
||
|
|
|
||
|
|
|
||
|
|
tests :: Session -> IO ()
|
||
|
|
tests sess = do
|
||
|
|
infoM "Pontarius.Xmpp.Tests" "RUNNING test barrage"
|
||
|
|
test_messagePing sess
|
||
|
|
test_IQPing sess
|
||
|
|
test_IQError sess
|
||
|
|
test_IQTimeout sess
|
||
|
|
infoM "Pontarius.Xmpp.Tests" "SUCCESS test barrage"
|
||
|
|
|
||
|
|
test :: IO ()
|
||
|
|
test = do
|
||
|
|
updateGlobalLogger "Pontarius.Xmpp" $ setLevel INFO
|
||
|
|
prepareThreads resp tests
|