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

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