@@ -1,11 +1,10 @@
1+{-# LANGUAGE RebindableSyntax, FlexibleInstances, OverlappingInstances, UndecidableInstances #-}
12module TestTransport where
23
3−import Prelude hiding (catch)
4+import Prelude hiding (catch, (>>=), (>>), return, fail)
45import TestAuxiliary (forkTry, runTests)
56import Control.Concurrent.MVar (newEmptyMVar, takeMVar, putMVar, readMVar)
67import Control.Monad (replicateM, replicateM_, when, guard, forM_)
7−import Control.Exception (evaluate, throw, catch, SomeException)
8−import Control.Applicative ((<$>))
98import Network.Transport
109import Network.Transport.Internal (tlog)
1110import Network.Transport.Util (spawn)
@@ -13,6 +12,8 @@ import Data.ByteString (ByteString)
1312import Data.ByteString.Char8 (pack)
1413import Data.Map (Map)
1514import qualified Data.Map as Map (empty, insert, delete, findWithDefault, adjust, null, toList, map)
15+import Data.String (fromString)
16+import Traced
1617
1718-- | Server that echoes messages straight back to the origin endpoint.
1819echoServer :: EndPoint -> IO ()
@@ -40,23 +41,6 @@ echoServer endpoint = do
4041 ErrorEvent _ ->
4142 fail (show event)
4243
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)
48− case mbool of
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
54−
55−-- | Like 'expect' but without a return value
56−expect' :: EndPoint -> (Event -> Bool) -> IO ()
57−expect' endpoint predicate =
58− expect endpoint (\event -> (predicate event, ()))
59−
6044-- | Ping client used in a few tests
6145ping :: EndPoint -> EndPointAddress -> Int -> ByteString -> IO ()
6246ping endpoint server numPings msg = do
@@ -66,13 +50,14 @@ ping endpoint server numPings msg = do
6650
6751 -- Wait for the server to open reply connection
6852 tlog "Wait for ConnectionOpened message"
69− cid <- expect endpoint (\(ConnectionOpened cid _ _) -> (True, cid))
53+ ConnectionOpened cid _ _ <- receive endpoint
7054
7155 -- Send pings and wait for reply
7256 tlog "Send ping and wait for reply"
7357 replicateM_ numPings $ do
7458 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
60+ return ()
7661
7762 -- Close the connection
7863 tlog "Close the connection"
@@ -80,7 +65,7 @@ ping endpoint server numPings msg = do
8065
8166 -- Wait for the server to close its connection to us
8267 tlog "Wait for ConnectionClosed message"
83− expect' endpoint (\(ConnectionClosed cid') -> cid == cid')
68+ ConnectionClosed cid' <- receive endpoint ; True <- return $ cid == cid'
8469
8570 -- Done
8671 tlog "Ping client done"
@@ -431,11 +416,11 @@ testCloseTwice transport _ = do
431416 close conn1
432417
433418 -- Verify expected response from the echo server
434− cid1 <- expect endpoint (\(ConnectionOpened cid _ _) -> (True, cid))
435− cid2 <- expect endpoint (\(ConnectionOpened cid _ _) -> (True, cid))
436− expect' endpoint (\(ConnectionClosed cid) -> cid == cid2)
437− expect' endpoint (\(Received cid msg) -> cid == cid1 && msg == ["ping"])
438− expect' endpoint (\(ConnectionClosed cid) -> cid == cid1)
419+ ConnectionOpened cid1 _ _ <- receive endpoint
420+ ConnectionOpened cid2 _ _ <- receive endpoint
421+ ConnectionClosed cid2' <- receive endpoint ; True <- return $ cid2' == cid2
422+ Received cid1' ["ping"] <- receive endpoint ; True <- return $ cid1' == cid1
423+ ConnectionClosed cid1'' <- receive endpoint ; True <- return $ cid1'' == cid1
439424
440425 putMVar clientDone ()
441426
@@ -467,19 +452,65 @@ testConnectToSelf transport numPings = do
467452 tlog $ "reading"
468453
469454 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
471456
472457 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'
460+ return ()
474461
475462 tlog "Waiting for ConnectionClosed"
476− expect' endpoint (\(ConnectionClosed cid') -> cid == cid')
463+ ConnectionClosed cid' <- receive endpoint ; True <- return $ cid == cid'
477464
478465 tlog "Done"
479466 putMVar done ()
480467
481468 takeMVar done
482469
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
475+
476+ tlog "Creating self-connection"
477+ Right conn1 <- connect endpoint (address endpoint) ReliableOrdered
478+ Right conn2 <- connect endpoint (address endpoint) ReliableOrdered
479+
480+ tlog "Talk to myself"
481+
482+ -- One thread to write to the endpoint using the first connection
483+ forkTry $ do
484+ tlog $ "writing"
485+
486+ tlog $ "Sending ping"
487+ replicateM_ numPings $ send conn1 ["pingA"]
488+
489+ tlog $ "Closing connection"
490+ close conn1
491+
492+ -- One thread to write to the endpoint using the second connection
493+ forkTry $ do
494+ tlog $ "writing"
495+
496+ tlog $ "Sending ping"
497+ replicateM_ numPings $ send conn2 ["pingB"]
498+
499+ tlog $ "Closing connection"
500+ close conn2
501+
502+ -- And one thread to read
503+ forkTry $ do
504+ tlog $ "reading"
505+
506+ [(_, events1), (_, events2)] <- collect endpoint (2 * (numPings + 2))
507+ True <- return $ events1 == replicate numPings ["pingA"]
508+ True <- return $ events2 == replicate numPings ["pingB"]
509+
510+ tlog "Done"
511+ putMVar done ()
512+
513+ takeMVar done
483514
484515-- Transport tests
485516testTransport :: Transport -> IO ()
@@ -494,6 +525,7 @@ testTransport transport = runTests
494525 , ("SendAfterClose", testSendAfterClose transport numPings)
495526 , ("CloseTwice", testCloseTwice transport numPings)
496527 , ("ConnectToSelf", testConnectToSelf transport numPings)
528+ , ("ConnectToSelfTwice", testConnectToSelfTwice transport numPings)
497529 ]
498530 where
499− numPings = 10000
531+ numPings = 10000 :: Int