@@ -1,11 +1,10 @@
1+{-# LANGUAGE RebindableSyntax, FlexibleInstances, OverlappingInstances, UndecidableInstances #-}
1module TestTransport where
2module TestTransport where
3−import Prelude hiding (catch)
4+import Prelude hiding (catch, (>>=), (>>), return, fail)
4import TestAuxiliary (forkTry, runTests)
5import TestAuxiliary (forkTry, runTests)
5import Control.Concurrent.MVar (newEmptyMVar, takeMVar, putMVar, readMVar)
6import Control.Concurrent.MVar (newEmptyMVar, takeMVar, putMVar, readMVar)
6import Control.Monad (replicateM, replicateM_, when, guard, forM_)
7import Control.Monad (replicateM, replicateM_, when, guard, forM_)
7−import Control.Exception (evaluate, throw, catch, SomeException)
8−import Control.Applicative ((<$>))
9import Network.Transport
8import Network.Transport
10import Network.Transport.Internal (tlog)
9import Network.Transport.Internal (tlog)
11import Network.Transport.Util (spawn)
10import Network.Transport.Util (spawn)
@@ -13,6 +12,8 @@ import Data.ByteString (ByteString)
13import Data.ByteString.Char8 (pack)
12import Data.ByteString.Char8 (pack)
14import Data.Map (Map)
13import Data.Map (Map)
15import qualified Data.Map as Map (empty, insert, delete, findWithDefault, adjust, null, toList, map)
14import qualified Data.Map as Map (empty, insert, delete, findWithDefault, adjust, null, toList, map)
15+import Data.String (fromString)
17-- | Server that echoes messages straight back to the origin endpoint.
18-- | Server that echoes messages straight back to the origin endpoint.
18echoServer :: EndPoint -> IO ()
19echoServer :: EndPoint -> IO ()
@@ -40,23 +41,6 @@ echoServer endpoint = do
40 ErrorEvent _ ->
41 ErrorEvent _ ->
41 fail (show event)
42 fail (show event)
43−-- | Wait for an event, throw an exception if the given predicate returns false
44−expect :: EndPoint -> (Event -> (Bool, a)) -> IO a
45−expect endpoint predicate = do
46− event <- receive endpoint
47− mbool <- catch (Right <$> evaluate (predicate event)) (return . Left)
49− Left err -> do tlog $ "Unexpected event " ++ show event
50− throw (err :: SomeException)
51− Right (False, _) -> do tlog $ "Unexpected event " ++ show event
52− fail "Unexpected event"
53− Right (True, a) -> return a
55−-- | Like 'expect' but without a return value
56−expect' :: EndPoint -> (Event -> Bool) -> IO ()
57−expect' endpoint predicate =
58− expect endpoint (\event -> (predicate event, ()))
60-- | Ping client used in a few tests
44-- | Ping client used in a few tests
61ping :: EndPoint -> EndPointAddress -> Int -> ByteString -> IO ()
45ping :: EndPoint -> EndPointAddress -> Int -> ByteString -> IO ()
62ping endpoint server numPings msg = do
46ping endpoint server numPings msg = do
@@ -66,13 +50,14 @@ ping endpoint server numPings msg = do
67 -- Wait for the server to open reply connection
51 -- Wait for the server to open reply connection
68 tlog "Wait for ConnectionOpened message"
52 tlog "Wait for ConnectionOpened message"
69− cid <- expect endpoint (\(ConnectionOpened cid _ _) -> (True, cid))
53+ ConnectionOpened cid _ _ <- receive endpoint
71 -- Send pings and wait for reply
55 -- Send pings and wait for reply
72 tlog "Send ping and wait for reply"
56 tlog "Send ping and wait for reply"
73 replicateM_ numPings $ do
57 replicateM_ numPings $ do
74 send conn [msg]
58 send conn [msg]
75− expect' endpoint (\(Received cid' [reply]) -> cid == cid' && reply == msg)
59+ Received cid' [reply] <- receive endpoint ; True <- return $ cid == cid' && reply == msg
77 -- Close the connection
62 -- Close the connection
78 tlog "Close the connection"
63 tlog "Close the connection"
@@ -80,7 +65,7 @@ ping endpoint server numPings msg = do
81 -- Wait for the server to close its connection to us
66 -- Wait for the server to close its connection to us
82 tlog "Wait for ConnectionClosed message"
67 tlog "Wait for ConnectionClosed message"
83− expect' endpoint (\(ConnectionClosed cid') -> cid == cid')
68+ ConnectionClosed cid' <- receive endpoint ; True <- return $ cid == cid'
86 tlog "Ping client done"
71 tlog "Ping client done"
@@ -431,11 +416,11 @@ testCloseTwice transport _ = do
431 close conn1
416 close conn1
433 -- Verify expected response from the echo server
418 -- Verify expected response from the echo server
434− cid1 <- expect endpoint (\(ConnectionOpened cid _ _) -> (True, cid))
419+ ConnectionOpened cid1 _ _ <- receive endpoint
435− cid2 <- expect endpoint (\(ConnectionOpened cid _ _) -> (True, cid))
420+ ConnectionOpened cid2 _ _ <- receive endpoint
436− expect' endpoint (\(ConnectionClosed cid) -> cid == cid2)
421+ ConnectionClosed cid2' <- receive endpoint ; True <- return $ cid2' == cid2
437− expect' endpoint (\(Received cid msg) -> cid == cid1 && msg == ["ping"])
422+ Received cid1' ["ping"] <- receive endpoint ; True <- return $ cid1' == cid1
438− expect' endpoint (\(ConnectionClosed cid) -> cid == cid1)
423+ ConnectionClosed cid1'' <- receive endpoint ; True <- return $ cid1'' == cid1
440 putMVar clientDone ()
425 putMVar clientDone ()
@@ -467,19 +452,65 @@ testConnectToSelf transport numPings = do
467 tlog $ "reading"
452 tlog $ "reading"
469 tlog "Waiting for ConnectionOpened"
454 tlog "Waiting for ConnectionOpened"
470− cid <- expect endpoint (\(ConnectionOpened cid _ addr) -> (addr == address endpoint, cid))
455+ ConnectionOpened cid _ addr <- receive endpoint ; True <- return $ addr == address endpoint
472 tlog "Waiting for Received"
457 tlog "Waiting for Received"
473− replicateM_ numPings $ expect' endpoint (\(Received cid' msg) -> cid == cid' && msg == ["ping"])
458+ replicateM_ numPings $ do
459+ Received cid' ["ping"] <- receive endpoint ; True <- return $ cid == cid'
475 tlog "Waiting for ConnectionClosed"
462 tlog "Waiting for ConnectionClosed"
476− expect' endpoint (\(ConnectionClosed cid') -> cid == cid')
463+ ConnectionClosed cid' <- receive endpoint ; True <- return $ cid == cid'
478 tlog "Done"
465 tlog "Done"
479 putMVar done ()
466 putMVar done ()
481 takeMVar done
468 takeMVar done
470+-- | Test that we can connect an endpoint to itself multiple times
471+testConnectToSelfTwice :: Transport -> Int -> IO ()
472+testConnectToSelfTwice transport numPings = do
473+ done <- newEmptyMVar
474+ Right endpoint <- newEndPoint transport
476+ tlog "Creating self-connection"
477+ Right conn1 <- connect endpoint (address endpoint) ReliableOrdered
478+ Right conn2 <- connect endpoint (address endpoint) ReliableOrdered
480+ tlog "Talk to myself"
482+ -- One thread to write to the endpoint using the first connection
486+ tlog $ "Sending ping"
487+ replicateM_ numPings $ send conn1 ["pingA"]
489+ tlog $ "Closing connection"
492+ -- One thread to write to the endpoint using the second connection
496+ tlog $ "Sending ping"
497+ replicateM_ numPings $ send conn2 ["pingB"]
499+ tlog $ "Closing connection"
502+ -- And one thread to read
506+ [(_, events1), (_, events2)] <- collect endpoint (2 * (numPings + 2))
507+ True <- return $ events1 == replicate numPings ["pingA"]
508+ True <- return $ events2 == replicate numPings ["pingB"]
484-- Transport tests
515-- Transport tests
485testTransport :: Transport -> IO ()
516testTransport :: Transport -> IO ()
@@ -494,6 +525,7 @@ testTransport transport = runTests
494 , ("SendAfterClose", testSendAfterClose transport numPings)
525 , ("SendAfterClose", testSendAfterClose transport numPings)
495 , ("CloseTwice", testCloseTwice transport numPings)
526 , ("CloseTwice", testCloseTwice transport numPings)
496 , ("ConnectToSelf", testConnectToSelf transport numPings)
527 , ("ConnectToSelf", testConnectToSelf transport numPings)
528+ , ("ConnectToSelfTwice", testConnectToSelfTwice transport numPings)
499− numPings = 10000
531+ numPings = 10000 :: Int