@@ -1,10 +1,9 @@
1module Main where
1module Main where
3import Prelude hiding (catch)
3import Prelude hiding (catch)
4−import Data.Binary (Binary)
4+import Data.Binary (Binary(..))
5import Data.Typeable (Typeable)
5import Data.Typeable (Typeable)
6import Data.Foldable (forM_)
6import Data.Foldable (forM_)
7−import qualified Data.Map as Map (empty)
8import Control.Concurrent (forkIO, threadDelay)
7import Control.Concurrent (forkIO, threadDelay)
9import Control.Concurrent.MVar ( MVar
8import Control.Concurrent.MVar ( MVar
10 , newEmptyMVar
9 , newEmptyMVar
@@ -15,7 +14,7 @@ import Control.Concurrent.MVar ( MVar
15import Control.Monad (replicateM_)
14import Control.Monad (replicateM_)
16import Control.Monad.IO.Class (liftIO)
15import Control.Monad.IO.Class (liftIO)
17import Control.Exception (throwIO)
16import Control.Exception (throwIO)
18−import Control.Applicative ((<$>))
17+import Control.Applicative ((<$>), (<*>))
19import qualified Network.Transport as NT (Transport, closeEndPoint)
18import qualified Network.Transport as NT (Transport, closeEndPoint)
20import Network.Transport.TCP (createTransport, defaultTCPParameters)
19import Network.Transport.TCP (createTransport, defaultTCPParameters)
21import Control.Distributed.Process
20import Control.Distributed.Process
@@ -44,13 +43,13 @@ testPing transport = do
46 forkIO $ do
45 forkIO $ do
47− localNode <- newLocalNode transport Map.empty
46+ localNode <- newLocalNode transport initRemoteCallMetaData
48 addr <- forkProcess localNode ping
47 addr <- forkProcess localNode ping
49 putMVar serverAddr addr
48 putMVar serverAddr addr
52 forkIO $ do
51 forkIO $ do
53− localNode <- newLocalNode transport Map.empty
52+ localNode <- newLocalNode transport initRemoteCallMetaData
54 pingServer <- readMVar serverAddr
53 pingServer <- readMVar serverAddr
56 let numPings = 10000
55 let numPings = 10000
@@ -118,13 +117,13 @@ testMonitorUnreachable transport mOrL un = do
118 done <- newEmptyMVar
117 done <- newEmptyMVar
120 forkIO $ do
119 forkIO $ do
121− localNode <- newLocalNode transport Map.empty
120+ localNode <- newLocalNode transport initRemoteCallMetaData
122 addr <- forkProcess localNode . liftIO $ threadDelay 1000000
121 addr <- forkProcess localNode . liftIO $ threadDelay 1000000
123 closeLocalNode localNode
122 closeLocalNode localNode
124 putMVar deadProcess addr
123 putMVar deadProcess addr
126 forkIO $ do
125 forkIO $ do
127− localNode <- newLocalNode transport Map.empty
126+ localNode <- newLocalNode transport initRemoteCallMetaData
128 theirAddr <- readMVar deadProcess
127 theirAddr <- readMVar deadProcess
129 runProcess localNode $
128 runProcess localNode $
130 monitorTestProcess theirAddr mOrL un DiedDisconnect Nothing done
129 monitorTestProcess theirAddr mOrL un DiedDisconnect Nothing done
@@ -139,13 +138,13 @@ testMonitorNormalTermination transport mOrL un = do
139 done <- newEmptyMVar
138 done <- newEmptyMVar
141 forkIO $ do
140 forkIO $ do
142− localNode <- newLocalNode transport Map.empty
141+ localNode <- newLocalNode transport initRemoteCallMetaData
143 addr <- forkProcess localNode $
142 addr <- forkProcess localNode $
144 liftIO $ readMVar monitorSetup
143 liftIO $ readMVar monitorSetup
145 putMVar monitoredProcess addr
144 putMVar monitoredProcess addr
147 forkIO $ do
146 forkIO $ do
148− localNode <- newLocalNode transport Map.empty
147+ localNode <- newLocalNode transport initRemoteCallMetaData
149 theirAddr <- readMVar monitoredProcess
148 theirAddr <- readMVar monitoredProcess
150 runProcess localNode $
149 runProcess localNode $
151 monitorTestProcess theirAddr mOrL un DiedNormal (Just monitorSetup) done
150 monitorTestProcess theirAddr mOrL un DiedNormal (Just monitorSetup) done
@@ -162,14 +161,14 @@ testMonitorAbnormalTermination transport mOrL un = do
162 let err = userError "Abnormal termination"
161 let err = userError "Abnormal termination"
164 forkIO $ do
163 forkIO $ do
165− localNode <- newLocalNode transport Map.empty
164+ localNode <- newLocalNode transport initRemoteCallMetaData
166 addr <- forkProcess localNode . liftIO $ do
165 addr <- forkProcess localNode . liftIO $ do
167 readMVar monitorSetup
166 readMVar monitorSetup
168 throwIO err
167 throwIO err
169 putMVar monitoredProcess addr
168 putMVar monitoredProcess addr
171 forkIO $ do
170 forkIO $ do
172− localNode <- newLocalNode transport Map.empty
171+ localNode <- newLocalNode transport initRemoteCallMetaData
173 theirAddr <- readMVar monitoredProcess
172 theirAddr <- readMVar monitoredProcess
174 runProcess localNode $
173 runProcess localNode $
175 monitorTestProcess theirAddr mOrL un (DiedException (show err)) (Just monitorSetup) done
174 monitorTestProcess theirAddr mOrL un (DiedException (show err)) (Just monitorSetup) done
@@ -181,7 +180,7 @@ testMonitorLocalDeadProcess :: NT.Transport -> Bool -> Bool -> IO ()
181testMonitorLocalDeadProcess transport mOrL un = do
180testMonitorLocalDeadProcess transport mOrL un = do
182 processDead <- newEmptyMVar
181 processDead <- newEmptyMVar
183 processAddr <- newEmptyMVar
182 processAddr <- newEmptyMVar
184− localNode <- newLocalNode transport Map.empty
183+ localNode <- newLocalNode transport initRemoteCallMetaData
185 done <- newEmptyMVar
184 done <- newEmptyMVar
187 forkIO $ do
186 forkIO $ do
@@ -204,12 +203,12 @@ testMonitorRemoteDeadProcess transport mOrL un = do
204 done <- newEmptyMVar
203 done <- newEmptyMVar
206 forkIO $ do
205 forkIO $ do
207− localNode <- newLocalNode transport Map.empty
206+ localNode <- newLocalNode transport initRemoteCallMetaData
208 addr <- forkProcess localNode . liftIO $ putMVar processDead ()
207 addr <- forkProcess localNode . liftIO $ putMVar processDead ()
209 putMVar processAddr addr
208 putMVar processAddr addr
211 forkIO $ do
210 forkIO $ do
212− localNode <- newLocalNode transport Map.empty
211+ localNode <- newLocalNode transport initRemoteCallMetaData
213 theirAddr <- readMVar processAddr
212 theirAddr <- readMVar processAddr
214 readMVar processDead
213 readMVar processDead
215 runProcess localNode $ do
214 runProcess localNode $ do
@@ -225,128 +224,83 @@ testMonitorDisconnect transport mOrL un = do
225 done <- newEmptyMVar
224 done <- newEmptyMVar
227 forkIO $ do
226 forkIO $ do
228− localNode <- newLocalNode transport Map.empty
227+ localNode <- newLocalNode transport initRemoteCallMetaData
229 addr <- forkProcess localNode . liftIO $ threadDelay 1000000
228 addr <- forkProcess localNode . liftIO $ threadDelay 1000000
230 putMVar processAddr addr
229 putMVar processAddr addr
231 readMVar monitorSetup
230 readMVar monitorSetup
232 NT.closeEndPoint (localEndPoint localNode)
231 NT.closeEndPoint (localEndPoint localNode)
234 forkIO $ do
233 forkIO $ do
235− localNode <- newLocalNode transport Map.empty
234+ localNode <- newLocalNode transport initRemoteCallMetaData
236 theirAddr <- readMVar processAddr
235 theirAddr <- readMVar processAddr
237 runProcess localNode $ do
236 runProcess localNode $ do
238 monitorTestProcess theirAddr mOrL un DiedDisconnect (Just monitorSetup) done
237 monitorTestProcess theirAddr mOrL un DiedDisconnect (Just monitorSetup) done
240 takeMVar done
239 takeMVar done
241+data Add = Add ProcessId Double Double deriving (Typeable)
242+data Divide = Divide ProcessId Double Double deriving (Typeable)
243+data DivByZero = DivByZero deriving (Typeable)
245+instance Binary Add where
246+ put (Add pid x y) = put pid >> put x >> put y
247+ get = Add <$> get <*> get <*> get
249+instance Binary Divide where
250+ put (Divide pid x y) = put pid >> put x >> put y
251+ get = Divide <$> get <*> get <*> get
253+instance Binary DivByZero where
254+ put DivByZero = return ()
255+ get = return DivByZero
260+ [ match (\(Add pid x y) -> send pid (x + y))
261+ , matchIf (\(Divide _ _ y) -> y /= 0)
262+ (\(Divide pid x y) -> send pid (x / y))
263+ , match (\(Divide pid _ _) -> send pid DivByZero)
243−{-
267+-- | Test the math server (i.e., receiveWait)
244−-- Like 'testMonitor1', but throw an exception instead
245−testMonitor2 :: NT.Transport -> IO ()
246−testMonitor2 transport = do
247− deadProcess <- newEmptyMVar
248− done <- newEmptyMVar
251− localNode <- newLocalNode transport Map.empty
252− addr <- forkProcess localNode $ return ()
253− closeLocalNode localNode
254− putMVar deadProcess addr
257− localNode <- newLocalNode transport Map.empty
258− theirAddr <- readMVar deadProcess
259− runProcess localNode $ do
260− monitor theirAddr MaLink
261− pcatch (send theirAddr "Hi") $ \(ProcessMonitorException pid SrNoPing) -> do
262− True <- return $ pid == theirAddr
268−-- The first send succeeds, connection is set up, but then the second send
271−-- TODO: should we specify that we receive exactly one notification per process
273−testMonitor3 :: NT.Transport -> IO ()
268+testMath :: NT.Transport -> IO ()
274−testMonitor3 transport = do
269+testMath transport = do
275− firstSend <- newEmptyMVar
276− serverAddr <- newEmptyMVar
270+ serverAddr <- newEmptyMVar
277− serverDead <- newEmptyMVar
278− done <- newEmptyMVar
271+ clientDone <- newEmptyMVar
280 forkIO $ do
274 forkIO $ do
281− localNode <- newLocalNode transport Map.empty
275+ localNode <- newLocalNode transport initRemoteCallMetaData
282− -- TODO: what happens when processes terminate?
283− addr <- forkProcess localNode $ return ()
276+ addr <- forkProcess localNode math
284 putMVar serverAddr addr
277 putMVar serverAddr addr
286− closeLocalNode localNode
287− threadDelay 10000 -- Give the TCP layer a chance to actually close the socket
288− putMVar serverDead ()
290 forkIO $ do
280 forkIO $ do
291− localNode <- newLocalNode transport Map.empty
281+ localNode <- newLocalNode transport initRemoteCallMetaData
292− theirAddr <- readMVar serverAddr
282+ mathServer <- readMVar serverAddr
293− runProcess localNode $ do
294− monitor theirAddr MaMonitor
296− liftIO $ putMVar firstSend () >> readMVar serverDead
298− ProcessMonitorException pid SrNoPing <- expect
299− True <- return $ pid == theirAddr
300− -- We should not receive a second exception
301− send theirAddr "Hey"
302− Nothing <- expectTimeout 1000000 :: Process (Maybe ProcessMonitorException)
309−-- Like testMonitor3, except without the second send (so we must detect the
310−-- failure elsewhere)
311−testMonitor4 :: NT.Transport -> IO ()
312−testMonitor4 transport = do
313− firstSend <- newEmptyMVar
314− serverAddr <- newEmptyMVar
315− serverDead <- newEmptyMVar
316− done <- newEmptyMVar
318− forkIO $ do
284+ runProcess localNode $ do
319− localNode <- newLocalNode transport Map.empty
285+ pid <- getSelfPid
320− -- TODO: what happens when processes terminate?
286+ send mathServer (Add pid 1 2)
321− addr <- forkProcess localNode $ return ()
287+ 3 <- expect :: Process Double
322− putMVar serverAddr addr
288+ send mathServer (Divide pid 8 2)
323− readMVar firstSend
289+ 4 <- expect :: Process Double
324− closeLocalNode localNode
290+ send mathServer (Divide pid 8 0)
325− threadDelay 10000 -- Give the TCP layer a chance to actually close the socket
291+ DivByZero <- expect
326− putMVar serverDead ()
292+ liftIO $ putMVar clientDone ()
329− localNode <- newLocalNode transport Map.empty
330− theirAddr <- readMVar serverAddr
331− runProcess localNode $ do
332− monitor theirAddr MaMonitor
334− liftIO $ putMVar firstSend () >> readMVar serverDead
335− ProcessMonitorException pid SrNoPing <- expect
336− True <- return $ pid == theirAddr
340− takeMVar done
294+ takeMVar clientDone
342−-- TODO: test/specify normal process termination
296+-- TODO: test timeout
345main :: IO ()
298main :: IO ()
347 Right transport <- createTransport "127.0.0.1" "8080" defaultTCPParameters
300 Right transport <- createTransport "127.0.0.1" "8080" defaultTCPParameters
348 runTests
301 runTests
349− [ ("Ping", testPing transport)
302+ [ ("Ping", testPing transport)
303+ , ("Math", testMath transport)
350 -- The "missing" combinations in the list below don't make much sense, as
304 -- The "missing" combinations in the list below don't make much sense, as
351 -- we cannot guarantee that the monitor reply or link exception will not
305 -- we cannot guarantee that the monitor reply or link exception will not
352 -- happen before the unmonitor or unlink
306 -- happen before the unmonitor or unlink
@@ -368,9 +322,4 @@ main = do
368 , ("UnlinkNormalTermination", testMonitorNormalTermination transport False True)
322 , ("UnlinkNormalTermination", testMonitorNormalTermination transport False True)
369 , ("UnlinkAbnormalTermination", testMonitorAbnormalTermination transport False True)
323 , ("UnlinkAbnormalTermination", testMonitorAbnormalTermination transport False True)
370 , ("UnlinkDisconnect", testMonitorDisconnect transport False True)
324 , ("UnlinkDisconnect", testMonitorDisconnect transport False True)
372− , ("Monitor2", testMonitor2 transport)
373− , ("Monitor3", testMonitor3 transport)
374− , ("Monitor4", testMonitor4 transport)