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.
168 lines
6.1 KiB
168 lines
6.1 KiB
{-# 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
|
|
|