@@ -9,6 +9,10 @@ import Data.ByteString (ByteString)
9import Data.ByteString.Char8 ()
9import Data.ByteString.Char8 ()
10import Data.Map (Map)
10import Data.Map (Map)
11import qualified Data.Map as Map (empty, insert, (!), delete)
11import qualified Data.Map as Map (empty, insert, (!), delete)
12+import Control.Monad.Reader (ReaderT, runReaderT, ask)
13+import Control.Monad.IO.Class (liftIO)
14+import System.IO (hFlush, stdout)
15+import System.Timeout (timeout)
13-- Logging (for debugging)
17-- Logging (for debugging)
14tlog :: String -> IO ()
18tlog :: String -> IO ()
@@ -80,7 +84,6 @@ testPingPong transport numPings = do
80 tlog "Ping client"
84 tlog "Ping client"
81 Right endpoint <- newEndPoint transport
85 Right endpoint <- newEndPoint transport
82 ping endpoint server numPings "ping"
86 ping endpoint server numPings "ping"
83− putStrLn $ "client did " ++ show numPings ++ " pings"
84 putMVar result ()
87 putMVar result ()
86 takeMVar result
89 takeMVar result
@@ -95,14 +98,12 @@ testEndPoints transport numPings = do
95 forkIO $ do
98 forkIO $ do
96 Right endpoint <- newEndPoint transport
99 Right endpoint <- newEndPoint transport
97 ping endpoint server numPings "pingA"
100 ping endpoint server numPings "pingA"
98− putStrLn $ "client A did " ++ show numPings ++ " pings"
99 putMVar resultA ()
101 putMVar resultA ()
101 -- Client B
103 -- Client B
102 forkIO $ do
104 forkIO $ do
103 Right endpoint <- newEndPoint transport
105 Right endpoint <- newEndPoint transport
104 ping endpoint server numPings "pingB"
106 ping endpoint server numPings "pingB"
105− putStrLn $ "client B did " ++ show numPings ++ " pings"
106 putMVar resultB ()
107 putMVar resultB ()
108 mapM_ takeMVar [resultA, resultB]
109 mapM_ takeMVar [resultA, resultB]
@@ -125,14 +126,10 @@ testConnections transport numPings = do
125 ConnectionOpened serv2 _ _ <- receive endpoint
126 ConnectionOpened serv2 _ _ <- receive endpoint
127 -- One thread to send "pingA" on the first connection
128 -- One thread to send "pingA" on the first connection
129− replicateM_ numPings $ send conn1 ["pingA"]
129+ forkIO $ replicateM_ numPings $ send conn1 ["pingA"]
130− putStrLn $ "client A did " ++ show numPings ++ " pings"
132 -- One thread to send "pingB" on the second connection
131 -- One thread to send "pingB" on the second connection
134− replicateM_ numPings $ send conn2 ["pingB"]
132+ forkIO $ replicateM_ numPings $ send conn2 ["pingB"]
135− putStrLn $ "client B did " ++ show numPings ++ " pings"
137 -- Verify server responses
134 -- Verify server responses
138 let verifyResponse 0 = putMVar result ()
135 let verifyResponse 0 = putMVar result ()
@@ -149,9 +146,64 @@ testConnections transport numPings = do
150 takeMVar result
147 takeMVar result
149+-- Test that closing one connection does not close the other
150+testCloseOneConnection :: Transport -> Int -> IO ()
151+testCloseOneConnection transport numPings = do
152+ server <- spawn transport echoServer
153+ result <- newEmptyMVar
157+ Right endpoint <- newEndPoint transport
159+ -- Open two connections to the server
160+ Right conn1 <- connect endpoint server ReliableOrdered
161+ ConnectionOpened serv1 _ _ <- receive endpoint
163+ Right conn2 <- connect endpoint server ReliableOrdered
164+ ConnectionOpened serv2 _ _ <- receive endpoint
166+ -- One thread to send "pingA" on the first connection
167+ forkIO $ replicateM_ numPings $ send conn1 ["pingA"] >> close conn1
169+ -- One thread to send "pingB" on the second connection
170+ forkIO $ replicateM_ (numPings * 2) $ send conn2 ["pingB"]
172+ -- Verify server responses
173+ let verifyResponse 0 = putMVar result ()
174+ verifyResponse n = do
175+ event <- receive endpoint
177+ Received cid [payload] -> do
178+ when (cid == serv1 && payload /= "pingA") $ error "Wrong message"
179+ when (cid == serv2 && payload /= "pingB") $ error "Wrong message"
180+ verifyResponse (n - 1)
183+ verifyResponse (3 * numPings)
187+runTestIO :: String -> IO () -> IO ()
188+runTestIO description test = do
189+ putStr $ "Running " ++ show description ++ ": "
194+runTest :: String -> (Transport -> Int -> IO ()) -> ReaderT Transport IO ()
195+runTest description test = do
197+ done <- liftIO $ timeout 1000000 $ runTestIO description (test transport 1000)
199+ Just () -> return ()
200+ Nothing -> error "timeout"
152-- Transport tests
203-- Transport tests
153testTransport :: Transport -> IO ()
204testTransport :: Transport -> IO ()
154−testTransport transport = do
205+testTransport = runReaderT $ do
155− testPingPong transport 10000
206+ runTest "PingPong" testPingPong
156− testEndPoints transport 10000
207+ runTest "EndPoints" testEndPoints
157− testConnections transport 10000
208+ runTest "Connections" testConnections
209+ runTest "CloseOneConnection" testCloseOneConnection