@@ -1,1339 +0,0 @@
1−module Main where
2−
3−#if ! MIN_VERSION_base(4,6,0)
4−import Prelude hiding (catch)
5−#endif
6−
7−import Data.Binary (Binary(..))
8−import Data.Typeable (Typeable)
9−import Data.Foldable (forM_)
10−import Control.Concurrent (forkIO, threadDelay, myThreadId, throwTo, ThreadId)
11−import Control.Concurrent.MVar
12− ( MVar
13− , newEmptyMVar
14− , putMVar
15− , takeMVar
16− , readMVar
17− )
18−import Control.Monad (replicateM_, replicateM, forever, void)
19−import Control.Exception (SomeException, throwIO)
20−import qualified Control.Exception as Ex (catch)
21−import Control.Applicative ((<$>), (<*>), pure, (<|>))
22−import qualified Network.Transport as NT (Transport, closeEndPoint)
23−import Network.Socket (sClose)
24−import Network.Transport.TCP
25− ( createTransportExposeInternals
26− , TransportInternals(socketBetween)
27− , defaultTCPParameters
28− )
29−import Control.Distributed.Process
30−import Control.Distributed.Process.Internal.Types
31− ( NodeId(nodeAddress)
32− , LocalNode(localEndPoint)
33− , ProcessExitException(..)
34− , nullProcessId
35− )
36−import Control.Distributed.Process.Node
37−import Control.Distributed.Process.Serializable (Serializable)
38−
39−import Test.HUnit (Assertion, assertFailure)
40−import Test.Framework (Test, defaultMain, testGroup)
41−import Test.Framework.Providers.HUnit (testCase)
42−import Control.Rematch hiding (match)
43−import Control.Rematch.Run (Match(..))
44−
45−newtype Ping = Ping ProcessId
46− deriving (Typeable, Binary, Show)
47−
48−newtype Pong = Pong ProcessId
49− deriving (Typeable, Binary, Show)
50−
51−--------------------------------------------------------------------------------
52−-- Supporting definitions --
53−--------------------------------------------------------------------------------
54−
55−expectThat :: a -> Matcher a -> Assertion
56−expectThat a matcher = case res of
57− MatchSuccess -> return ()
58− (MatchFailure msg) -> assertFailure msg
59− where res = runMatch matcher a
60−
61−-- | Like fork, but throw exceptions in the child thread to the parent
62−forkTry :: IO () -> IO ThreadId
63−forkTry p = do
64− tid <- myThreadId
65− forkIO $ Ex.catch p (\e -> throwTo tid (e :: SomeException))
66−
67−-- | The ping server from the paper
68−ping :: Process ()
69−ping = do
70− Pong partner <- expect
71− self <- getSelfPid
72− send partner (Ping self)
73− ping
74−
75−-- | Quick and dirty synchronous version of whereisRemoteAsync
76−whereisRemote :: NodeId -> String -> Process (Maybe ProcessId)
77−whereisRemote nid string = do
78− whereisRemoteAsync nid string
79− WhereIsReply _ mPid <- expect
80− return mPid
81−
82−data Add = Add ProcessId Double Double deriving (Typeable)
83−data Divide = Divide ProcessId Double Double deriving (Typeable)
84−data DivByZero = DivByZero deriving (Typeable)
85−
86−instance Binary Add where
87− put (Add pid x y) = put pid >> put x >> put y
88− get = Add <$> get <*> get <*> get
89−
90−instance Binary Divide where
91− put (Divide pid x y) = put pid >> put x >> put y
92− get = Divide <$> get <*> get <*> get
93−
94−instance Binary DivByZero where
95− put DivByZero = return ()
96− get = return DivByZero
97−
98−-- The math server from the paper
99−math :: Process ()
100−math = do
101− receiveWait
102− [ match (\(Add pid x y) -> send pid (x + y))
103− , matchIf (\(Divide _ _ y) -> y /= 0)
104− (\(Divide pid x y) -> send pid (x / y))
105− , match (\(Divide pid _ _) -> send pid DivByZero)
106− ]
107− math
108−
109−-- | Monitor or link to a remote node
110−monitorOrLink :: Bool -- ^ 'True' for monitor, 'False' for link
111− -> ProcessId -- Process to monitor/link to
112− -> Maybe (MVar ()) -- MVar to signal on once the monitor has been set up
113− -> Process (Maybe MonitorRef)
114−monitorOrLink mOrL pid mSignal = do
115− result <- if mOrL then Just <$> monitor pid
116− else link pid >> return Nothing
117− -- Monitor is asynchronous, which usually does not matter but if we want a
118− -- *specific* signal then it does. Therefore we wait an arbitrary delay and
119− -- hope that this means the monitor has been set up
120− forM_ mSignal $ \signal -> liftIO . forkIO $ threadDelay 100000 >> putMVar signal ()
121− return result
122−
123−monitorTestProcess :: ProcessId -- Process to monitor/link to
124− -> Bool -- 'True' for monitor, 'False' for link
125− -> Bool -- Should we unmonitor?
126− -> DiedReason -- Expected cause of death
127− -> Maybe (MVar ()) -- Signal for 'monitor set up'
128− -> MVar () -- Signal for successful termination
129− -> Process ()
130−monitorTestProcess theirAddr mOrL un reason monitorSetup done =
131− catch (do mRef <- monitorOrLink mOrL theirAddr monitorSetup
132− case (un, mRef) of
133− (True, Nothing) -> do
134− unlink theirAddr
135− liftIO $ putMVar done ()
136− (True, Just ref) -> do
137− unmonitor ref
138− liftIO $ putMVar done ()
139− (False, ref) -> do
140− ProcessMonitorNotification ref' pid reason' <- expect
141− True <- return $ Just ref' == ref && pid == theirAddr && mOrL && reason == reason'
142− liftIO $ putMVar done ()
143− )
144− (\(ProcessLinkException pid reason') -> do
145− True <- return $ pid == theirAddr && not mOrL && not un && reason == reason'
146− liftIO $ putMVar done ()
147− )
148−
149−--------------------------------------------------------------------------------
150−-- The tests proper --
151−--------------------------------------------------------------------------------
152−
153−-- | Basic ping test
154−testPing :: NT.Transport -> Assertion
155−testPing transport = do
156− serverAddr <- newEmptyMVar
157− clientDone <- newEmptyMVar
158−
159− -- Server
160− forkIO $ do
161− localNode <- newLocalNode transport initRemoteTable
162− addr <- forkProcess localNode ping
163− putMVar serverAddr addr
164−
165− -- Client
166− forkIO $ do
167− localNode <- newLocalNode transport initRemoteTable
168− pingServer <- readMVar serverAddr
169−
170− let numPings = 10000
171−
172− runProcess localNode $ do
173− pid <- getSelfPid
174− replicateM_ numPings $ do
175− send pingServer (Pong pid)
176− Ping _ <- expect
177− return ()
178−
179− putMVar clientDone ()
180−
181− takeMVar clientDone
182−
183−-- | Monitor a process on an unreachable node
184−testMonitorUnreachable :: NT.Transport -> Bool -> Bool -> Assertion
185−testMonitorUnreachable transport mOrL un = do
186− deadProcess <- newEmptyMVar
187− done <- newEmptyMVar
188−
189− forkIO $ do
190− localNode <- newLocalNode transport initRemoteTable
191− addr <- forkProcess localNode . liftIO $ threadDelay 1000000
192− closeLocalNode localNode
193− putMVar deadProcess addr
194−
195− forkIO $ do
196− localNode <- newLocalNode transport initRemoteTable
197− theirAddr <- readMVar deadProcess
198− runProcess localNode $
199− monitorTestProcess theirAddr mOrL un DiedDisconnect Nothing done
200−
201− takeMVar done
202−
203−-- | Monitor a process which terminates normally
204−testMonitorNormalTermination :: NT.Transport -> Bool -> Bool -> Assertion
205−testMonitorNormalTermination transport mOrL un = do
206− monitorSetup <- newEmptyMVar
207− monitoredProcess <- newEmptyMVar
208− done <- newEmptyMVar
209−
210− forkIO $ do
211− localNode <- newLocalNode transport initRemoteTable
212− addr <- forkProcess localNode $
213− liftIO $ readMVar monitorSetup
214− putMVar monitoredProcess addr
215−
216− forkIO $ do
217− localNode <- newLocalNode transport initRemoteTable
218− theirAddr <- readMVar monitoredProcess
219− runProcess localNode $
220− monitorTestProcess theirAddr mOrL un DiedNormal (Just monitorSetup) done
221−
222− takeMVar done
223−
224−-- | Monitor a process which terminates abnormally
225−testMonitorAbnormalTermination :: NT.Transport -> Bool -> Bool -> Assertion
226−testMonitorAbnormalTermination transport mOrL un = do
227− monitorSetup <- newEmptyMVar
228− monitoredProcess <- newEmptyMVar
229− done <- newEmptyMVar
230−
231− let err = userError "Abnormal termination"
232−
233− forkIO $ do
234− localNode <- newLocalNode transport initRemoteTable
235− addr <- forkProcess localNode . liftIO $ do
236− readMVar monitorSetup
237− throwIO err
238− putMVar monitoredProcess addr
239−
240− forkIO $ do
241− localNode <- newLocalNode transport initRemoteTable
242− theirAddr <- readMVar monitoredProcess
243− runProcess localNode $
244− monitorTestProcess theirAddr mOrL un (DiedException (show err)) (Just monitorSetup) done
245−
246− takeMVar done
247−
248−-- | Monitor a local process that is already dead
249−testMonitorLocalDeadProcess :: NT.Transport -> Bool -> Bool -> Assertion
250−testMonitorLocalDeadProcess transport mOrL un = do
251− processDead <- newEmptyMVar
252− processAddr <- newEmptyMVar
253− localNode <- newLocalNode transport initRemoteTable
254− done <- newEmptyMVar
255−
256− forkIO $ do
257− addr <- forkProcess localNode . liftIO $ putMVar processDead ()
258− putMVar processAddr addr
259−
260− forkIO $ do
261− theirAddr <- readMVar processAddr
262− readMVar processDead
263− runProcess localNode $ do
264− monitorTestProcess theirAddr mOrL un DiedUnknownId Nothing done
265−
266− takeMVar done
267−
268−-- | Monitor a remote process that is already dead
269−testMonitorRemoteDeadProcess :: NT.Transport -> Bool -> Bool -> Assertion
270−testMonitorRemoteDeadProcess transport mOrL un = do
271− processDead <- newEmptyMVar
272− processAddr <- newEmptyMVar
273− done <- newEmptyMVar
274−
275− forkIO $ do
276− localNode <- newLocalNode transport initRemoteTable
277− addr <- forkProcess localNode . liftIO $ putMVar processDead ()
278− putMVar processAddr addr
279−
280− forkIO $ do
281− localNode <- newLocalNode transport initRemoteTable
282− theirAddr <- readMVar processAddr
283− readMVar processDead
284− runProcess localNode $ do
285− monitorTestProcess theirAddr mOrL un DiedUnknownId Nothing done
286−
287− takeMVar done
288−
289−-- | Monitor a process that becomes disconnected
290−testMonitorDisconnect :: NT.Transport -> Bool -> Bool -> Assertion
291−testMonitorDisconnect transport mOrL un = do
292− processAddr <- newEmptyMVar
293− monitorSetup <- newEmptyMVar
294− done <- newEmptyMVar
295−
296− forkIO $ do
297− localNode <- newLocalNode transport initRemoteTable
298− addr <- forkProcess localNode . liftIO $ threadDelay 1000000
299− putMVar processAddr addr
300− readMVar monitorSetup
301− NT.closeEndPoint (localEndPoint localNode)
302−
303− forkIO $ do
304− localNode <- newLocalNode transport initRemoteTable
305− theirAddr <- readMVar processAddr
306− runProcess localNode $ do
307− monitorTestProcess theirAddr mOrL un DiedDisconnect (Just monitorSetup) done
308−
309− takeMVar done
310−
311−-- | Test the math server (i.e., receiveWait)
312−testMath :: NT.Transport -> Assertion
313−testMath transport = do
314− serverAddr <- newEmptyMVar
315− clientDone <- newEmptyMVar
316−
317− -- Server
318− forkIO $ do
319− localNode <- newLocalNode transport initRemoteTable
320− addr <- forkProcess localNode math
321− putMVar serverAddr addr
322−
323− -- Client
324− forkIO $ do
325− localNode <- newLocalNode transport initRemoteTable
326− mathServer <- readMVar serverAddr
327−
328− runProcess localNode $ do
329− pid <- getSelfPid
330− send mathServer (Add pid 1 2)
331− 3 <- expect :: Process Double
332− send mathServer (Divide pid 8 2)
333− 4 <- expect :: Process Double
334− send mathServer (Divide pid 8 0)
335− DivByZero <- expect
336− liftIO $ putMVar clientDone ()
337−
338− takeMVar clientDone
339−
340−-- | Send first message (i.e. connect) to an already terminated process
341−-- (without monitoring); then send another message to a second process on
342−-- the same remote node (we're checking that the remote node did not die)
343−testSendToTerminated :: NT.Transport -> Assertion
344−testSendToTerminated transport = do
345− serverAddr1 <- newEmptyMVar
346− serverAddr2 <- newEmptyMVar
347− clientDone <- newEmptyMVar
348−
349− forkIO $ do
350− terminated <- newEmptyMVar
351− localNode <- newLocalNode transport initRemoteTable
352− addr1 <- forkProcess localNode $ liftIO $ putMVar terminated ()
353− addr2 <- forkProcess localNode $ ping
354− readMVar terminated
355− putMVar serverAddr1 addr1
356− putMVar serverAddr2 addr2
357−
358− forkIO $ do
359− localNode <- newLocalNode transport initRemoteTable
360− server1 <- readMVar serverAddr1
361− server2 <- readMVar serverAddr2
362− runProcess localNode $ do
363− pid <- getSelfPid
364− send server1 "Hi"
365− send server2 (Pong pid)
366− Ping pid' <- expect
367− True <- return $ pid' == server2
368− liftIO $ putMVar clientDone ()
369−
370− takeMVar clientDone
371−
372−-- | Test (non-zero) timeout
373−testTimeout :: NT.Transport -> Assertion
374−testTimeout transport = do
375− localNode <- newLocalNode transport initRemoteTable
376− done <- newEmptyMVar
377−
378− runProcess localNode $ do
379− Nothing <- receiveTimeout 1000000 [match (\(Add _ _ _) -> return ())]
380− liftIO $ putMVar done ()
381−
382− takeMVar done
383−
384−-- | Test zero timeout
385−testTimeout0 :: NT.Transport -> Assertion
386−testTimeout0 transport = do
387− serverAddr <- newEmptyMVar
388− clientDone <- newEmptyMVar
389− messagesSent <- newEmptyMVar
390−
391− forkIO $ do
392− localNode <- newLocalNode transport initRemoteTable
393− addr <- forkProcess localNode $ do
394− liftIO $ readMVar messagesSent >> threadDelay 1000000
395− -- Variation on the venerable ping server which uses a zero timeout
396− -- Since we wait for all messages to be sent before doing this receive,
397− -- we should nevertheless find the right message immediately
398− Just partner <- receiveTimeout 0 [match (\(Pong partner) -> return partner)]
399− self <- getSelfPid
400− send partner (Ping self)
401− putMVar serverAddr addr
402−
403− forkIO $ do
404− localNode <- newLocalNode transport initRemoteTable
405− server <- readMVar serverAddr
406− runProcess localNode $ do
407− pid <- getSelfPid
408− -- Send a bunch of messages. A large number of messages that the server
409− -- is not interested in, and then a single message that it wants
410− replicateM_ 10000 $ send server "Irrelevant message"
411− send server (Pong pid)
412− liftIO $ putMVar messagesSent ()
413− Ping _ <- expect
414− liftIO $ putMVar clientDone ()
415−
416− takeMVar clientDone
417−
418−-- | Test typed channels
419−testTypedChannels :: NT.Transport -> Assertion
420−testTypedChannels transport = do
421− serverChannel <- newEmptyMVar :: IO (MVar (SendPort (SendPort Bool, Int)))
422− clientDone <- newEmptyMVar
423−
424− forkIO $ do
425− localNode <- newLocalNode transport initRemoteTable
426− forkProcess localNode $ do
427− (serverSendPort, rport) <- newChan
428− liftIO $ putMVar serverChannel serverSendPort
429− (clientSendPort, i) <- receiveChan rport
430− sendChan clientSendPort (even i)
431− return ()
432−
433− forkIO $ do
434− localNode <- newLocalNode transport initRemoteTable
435− serverSendPort <- readMVar serverChannel
436− runProcess localNode $ do
437− (clientSendPort, rport) <- newChan
438− sendChan serverSendPort (clientSendPort, 5)
439− False <- receiveChan rport
440− liftIO $ putMVar clientDone ()
441−
442− takeMVar clientDone
443−
444−-- | Test merging receive ports
445−testMergeChannels :: NT.Transport -> Assertion
446−testMergeChannels transport = do
447− localNode <- newLocalNode transport initRemoteTable
448− testFlat localNode True "aaabbbccc"
449− testFlat localNode False "abcabcabc"
450− testNested localNode True True "aaabbbcccdddeeefffggghhhiii"
451− testNested localNode True False "adgadgadgbehbehbehcficficfi"
452− testNested localNode False True "abcabcabcdefdefdefghighighi"
453− testNested localNode False False "adgbehcfiadgbehcfiadgbehcfi"
454− testBlocked localNode True
455− testBlocked localNode False
456− where
457− -- Single layer of merging
458− testFlat :: LocalNode -> Bool -> String -> IO ()
459− testFlat localNode biased expected = do
460− done <- newEmptyMVar
461− forkProcess localNode $ do
462− rs <- mapM charChannel "abc"
463− m <- mergePorts biased rs
464− xs <- replicateM 9 $ receiveChan m
465− True <- return $ xs == expected
466− liftIO $ putMVar done ()
467− takeMVar done
468−
469− -- Two layers of merging
470− testNested :: LocalNode -> Bool -> Bool -> String -> IO ()
471− testNested localNode biasedInner biasedOuter expected = do
472− done <- newEmptyMVar
473− forkProcess localNode $ do
474− rss <- mapM (mapM charChannel) ["abc", "def", "ghi"]
475− ms <- mapM (mergePorts biasedInner) rss
476− m <- mergePorts biasedOuter ms
477− xs <- replicateM (9 * 3) $ receiveChan m
478− True <- return $ xs == expected
479− liftIO $ putMVar done ()
480− takeMVar done
481−
482− -- Test that if no messages are (immediately) available, the scheduler makes no difference
483− testBlocked :: LocalNode -> Bool -> IO ()
484− testBlocked localNode biased = do
485− vs <- replicateM 3 newEmptyMVar
486− done <- newEmptyMVar
487−
488− forkProcess localNode $ do
489− [sa, sb, sc] <- liftIO $ mapM readMVar vs
490− mapM_ ((>> liftIO (threadDelay 10000)) . uncurry sendChan)
491− [ -- a, b, c
492− (sa, 'a')
493− , (sb, 'b')
494− , (sc, 'c')
495− -- a, c, b
496− , (sa, 'a')
497− , (sc, 'c')
498− , (sb, 'b')
499− -- b, a, c
500− , (sb, 'b')
501− , (sa, 'a')
502− , (sc, 'c')
503− -- b, c, a
504− , (sb, 'b')
505− , (sc, 'c')
506− , (sa, 'a')
507− -- c, a, b
508− , (sc, 'c')
509− , (sa, 'a')
510− , (sb, 'b')
511− -- c, b, a
512− , (sc, 'c')
513− , (sb, 'b')
514− , (sa, 'a')
515− ]
516−
517− forkProcess localNode $ do
518− (ss, rs) <- unzip <$> replicateM 3 newChan
519− liftIO $ mapM_ (uncurry putMVar) $ zip vs ss
520− m <- mergePorts biased rs
521− xs <- replicateM (6 * 3) $ receiveChan m
522− True <- return $ xs == "abcacbbacbcacabcba"
523− liftIO $ putMVar done ()
524−
525− takeMVar done
526−
527− mergePorts :: Serializable a => Bool -> [ReceivePort a] -> Process (ReceivePort a)
528− mergePorts True = mergePortsBiased
529− mergePorts False = mergePortsRR
530−
531− charChannel :: Char -> Process (ReceivePort Char)
532− charChannel c = do
533− (sport, rport) <- newChan
534− replicateM_ 3 $ sendChan sport c
535− liftIO $ threadDelay 10000 -- Make sure messages have been sent
536− return rport
537−
538−testTerminate :: NT.Transport -> Assertion
539−testTerminate transport = do
540− localNode <- newLocalNode transport initRemoteTable
541− done <- newEmptyMVar
542−
543− pid <- forkProcess localNode $ do
544− liftIO $ threadDelay 100000
545− terminate
546−
547− runProcess localNode $ do
548− ref <- monitor pid
549− ProcessMonitorNotification ref' pid' (DiedException ex) <- expect
550− True <- return $ ref == ref' && pid == pid' && ex == show ProcessTerminationException
551− liftIO $ putMVar done ()
552−
553− takeMVar done
554−
555−testMonitorNode :: NT.Transport -> Assertion
556−testMonitorNode transport = do
557− [node1, node2] <- replicateM 2 $ newLocalNode transport initRemoteTable
558− done <- newEmptyMVar
559−
560− closeLocalNode node1
561−
562− runProcess node2 $ do
563− ref <- monitorNode (localNodeId node1)
564− NodeMonitorNotification ref' nid DiedDisconnect <- expect
565− True <- return $ ref == ref' && nid == localNodeId node1
566− liftIO $ putMVar done ()
567−
568− takeMVar done
569−
570−testMonitorLiveNode :: NT.Transport -> Assertion
571−testMonitorLiveNode transport = do
572− [node1, node2] <- replicateM 2 $ newLocalNode transport initRemoteTable
573− ready <- newEmptyMVar
574− done <- newEmptyMVar
575−
576− forkProcess node2 $ do
577− ref <- monitorNode (localNodeId node1)
578− liftIO $ putMVar ready ()
579− NodeMonitorNotification ref' nid _ <- expect
580− True <- return $ ref == ref' && nid == localNodeId node1
581− liftIO $ putMVar done ()
582−
583− takeMVar ready
584− closeLocalNode node1
585−
586− takeMVar done
587−
588−testMonitorChannel :: NT.Transport -> Assertion
589−testMonitorChannel transport = do
590− [node1, node2] <- replicateM 2 $ newLocalNode transport initRemoteTable
591− gotNotification <- newEmptyMVar
592−
593− pid <- forkProcess node1 $ do
594− sport <- expect :: Process (SendPort ())
595− ref <- monitorPort sport
596− PortMonitorNotification ref' port' reason <- expect
597− -- reason might be DiedUnknownId if the receive port is GCed before the
598− -- monitor is established (TODO: not sure that this is reasonable)
599− return $ ref' == ref && port' == sendPortId sport && (reason == DiedNormal || reason == DiedUnknownId)
600− liftIO $ putMVar gotNotification ()
601−
602− runProcess node2 $ do
603− (sport, _) <- newChan :: Process (SendPort (), ReceivePort ())
604− send pid sport
605− liftIO $ threadDelay 100000
606−
607− takeMVar gotNotification
608−
609−testRegistry :: NT.Transport -> Assertion
610−testRegistry transport = do
611− node <- newLocalNode transport initRemoteTable
612− done <- newEmptyMVar
613−
614− pingServer <- forkProcess node ping
615−
616− runProcess node $ do
617− register "ping" pingServer
618− Just pid <- whereis "ping"
619− True <- return $ pingServer == pid
620− us <- getSelfPid
621− nsend "ping" (Pong us)
622− Ping pid' <- expect
623− True <- return $ pingServer == pid'
624− liftIO $ putMVar done ()
625−
626− takeMVar done
627−
628−testRemoteRegistry :: NT.Transport -> Assertion
629−testRemoteRegistry transport = do
630− node1 <- newLocalNode transport initRemoteTable
631− node2 <- newLocalNode transport initRemoteTable
632− done <- newEmptyMVar
633−
634− pingServer <- forkProcess node1 ping
635−
636− runProcess node2 $ do
637− let nid1 = localNodeId node1
638− registerRemoteAsync nid1 "ping" pingServer
639− receiveWait [
640− matchIf (\(RegisterReply label' _) -> "ping" == label')
641− (\(RegisterReply _ _) -> return ()) ]
642−
643− Just pid <- whereisRemote nid1 "ping"
644− True <- return $ pingServer == pid
645− us <- getSelfPid
646− nsendRemote nid1 "ping" (Pong us)
647− Ping pid' <- expect
648− True <- return $ pingServer == pid'
649− liftIO $ putMVar done ()
650−
651− takeMVar done
652−
653−testSpawnLocal :: NT.Transport -> Assertion
654−testSpawnLocal transport = do
655− node <- newLocalNode transport initRemoteTable
656− done <- newEmptyMVar
657−
658− runProcess node $ do
659− us <- getSelfPid
660−
661− pid <- spawnLocal $ do
662− sport <- expect
663− sendChan sport (1234 :: Int)
664−
665− sport <- spawnChannelLocal $ \rport -> do
666− (1234 :: Int) <- receiveChan rport
667− send us ()
668−
669− send pid sport
670− () <- expect
671− liftIO $ putMVar done ()
672−
673− takeMVar done
674−
675−testReconnect :: NT.Transport -> TransportInternals -> Assertion
676−testReconnect transport transportInternals = do
677− [node1, node2] <- replicateM 2 $ newLocalNode transport initRemoteTable
678− let nid1 = localNodeId node1
679− nid2 = localNodeId node2
680− processA <- newEmptyMVar
681− [sendTestOk, registerTestOk] <- replicateM 2 newEmptyMVar
682−
683− forkProcess node1 $ do
684− us <- getSelfPid
685− liftIO $ putMVar processA us
686− msg1 <- expect
687− msg2 <- expect
688− True <- return $ msg1 == "message 1" && msg2 == "message 3"
689− liftIO $ putMVar sendTestOk ()
690−
691− forkProcess node2 $ do
692− {-
693− - Make sure there is no implicit reconnect on normal message sending
694− -}
695−
696− them <- liftIO $ readMVar processA
697− send them "message 1" >> liftIO (threadDelay 100000)
698−
699− -- Simulate network failure
700− liftIO $ do
701− sock <- socketBetween transportInternals (nodeAddress nid1) (nodeAddress nid2)
702− sClose sock
703− threadDelay 10000
704−
705− -- Should not arrive
706− send them "message 2"
707−
708− -- Should arrive
709− reconnect them
710− send them "message 3"
711−
712− liftIO $ takeMVar sendTestOk
713−
714− {-
715− - Test that there *is* implicit reconnect on node controller messages
716− -}
717−
718− us <- getSelfPid
719− registerRemoteAsync nid1 "a" us -- registerRemote is asynchronous
720− receiveWait [
721− matchIf (\(RegisterReply label' _) -> "a" == label')
722− (\(RegisterReply _ _) -> return ()) ]
723−
724− Just _ <- whereisRemote nid1 "a"
725−
726−
727− -- Simulate network failure
728− liftIO $ do
729− sock <- socketBetween transportInternals (nodeAddress nid1) (nodeAddress nid2)
730− sClose sock
731− threadDelay 10000
732−
733− -- This will happen due to implicit reconnect
734− registerRemoteAsync nid1 "b" us
735− receiveWait [
736− matchIf (\(RegisterReply label' _) -> "b" == label')
737− (\(RegisterReply _ _) -> return ()) ]
738−
739− -- Should happen
740− registerRemoteAsync nid1 "c" us
741− receiveWait [
742− matchIf (\(RegisterReply label' _) -> "c" == label')
743− (\(RegisterReply _ _) -> return ()) ]
744−
745− -- Check
746− Nothing <- whereisRemote nid1 "a" -- this will fail because the name is removed when the node is disconnected
747− Just _ <- whereisRemote nid1 "b" -- this will suceed because the value is set after thereconnect
748− Just _ <- whereisRemote nid1 "c"
749−
750− liftIO $ putMVar registerTestOk ()
751−
752− takeMVar registerTestOk
753−
754−-- | Test 'matchAny'. This repeats the 'testMath' but with a proxy server
755−-- in between
756−testMatchAny :: NT.Transport -> Assertion
757−testMatchAny transport = do
758− proxyAddr <- newEmptyMVar
759− clientDone <- newEmptyMVar
760−
761− -- Math server
762− forkIO $ do
763− localNode <- newLocalNode transport initRemoteTable
764− mathServer <- forkProcess localNode math
765− proxyServer <- forkProcess localNode $ forever $ do
766− msg <- receiveWait [ matchAny return ]
767− forward msg mathServer
768− putMVar proxyAddr proxyServer
769−
770− -- Client
771− forkIO $ do
772− localNode <- newLocalNode transport initRemoteTable
773− mathServer <- readMVar proxyAddr
774−
775− runProcess localNode $ do
776− pid <- getSelfPid
777− send mathServer (Add pid 1 2)
778− 3 <- expect :: Process Double
779− send mathServer (Divide pid 8 2)
780− 4 <- expect :: Process Double
781− send mathServer (Divide pid 8 0)
782− DivByZero <- expect
783− liftIO $ putMVar clientDone ()
784−
785− takeMVar clientDone
786−
787−-- | Test 'matchAny'. This repeats the 'testMath' but with a proxy server
788−-- in between, however we block 'Divide' requests ....
789−testMatchAnyHandle :: NT.Transport -> Assertion
790−testMatchAnyHandle transport = do
791− proxyAddr <- newEmptyMVar
792− clientDone <- newEmptyMVar
793−
794− -- Math server
795− forkIO $ do
796− localNode <- newLocalNode transport initRemoteTable
797− mathServer <- forkProcess localNode math
798− proxyServer <- forkProcess localNode $ forever $ do
799− receiveWait [
800− matchAny (maybeForward mathServer)
801− ]
802− putMVar proxyAddr proxyServer
803−
804− -- Client
805− forkIO $ do
806− localNode <- newLocalNode transport initRemoteTable
807− mathServer <- readMVar proxyAddr
808−
809− runProcess localNode $ do
810− pid <- getSelfPid
811− send mathServer (Add pid 1 2)
812− 3 <- expect :: Process Double
813− send mathServer (Divide pid 8 2)
814− Nothing <- (expectTimeout 100000) :: Process (Maybe Double)
815− liftIO $ putMVar clientDone ()
816−
817− takeMVar clientDone
818− where maybeForward :: ProcessId -> Message -> Process (Maybe ())
819− maybeForward s msg =
820− handleMessage msg (\m@(Add _ _ _) -> send s m)
821−
822−testMatchAnyNoHandle :: NT.Transport -> Assertion
823−testMatchAnyNoHandle transport = do
824− addr <- newEmptyMVar
825− clientDone <- newEmptyMVar
826− serverDone <- newEmptyMVar
827−
828− -- Math server
829− forkIO $ do
830− localNode <- newLocalNode transport initRemoteTable
831− server <- forkProcess localNode $ forever $ do
832− receiveWait [
833− matchAnyIf
834− -- the condition has type `Add -> Bool`
835− (\(Add _ _ _) -> True)
836− -- the match `AbstractMessage -> Process ()` will succeed!
837− (\m -> do
838− -- `String -> Process ()` does *not* match the input types however
839− r <- (handleMessage m (\(_ :: String) -> die "NONSENSE" ))
840− case r of
841− Nothing -> return ()
842− Just _ -> die "NONSENSE")
843− ]
844− -- we *must* have removed the message from our mailbox though!!!
845− Nothing <- receiveTimeout 100000 [ match (\(Add _ _ _) -> return ()) ]
846− liftIO $ putMVar serverDone ()
847− putMVar addr server
848−
849− -- Client
850− forkIO $ do
851− localNode <- newLocalNode transport initRemoteTable
852− server <- readMVar addr
853−
854− runProcess localNode $ do
855− pid <- getSelfPid
856− send server (Add pid 1 2)
857− -- we only care about the client having sent a message, so we're done
858− liftIO $ putMVar clientDone ()
859−
860− takeMVar clientDone
861− takeMVar serverDone
862−
863−-- | Test 'matchAnyIf'. We provide an /echo/ server, but it ignores requests
864−-- unless the text body @/= "bar"@ - this case should time out rather than
865−-- removing the message from the process mailbox.
866−testMatchAnyIf :: NT.Transport -> Assertion
867−testMatchAnyIf transport = do
868− echoAddr <- newEmptyMVar
869− clientDone <- newEmptyMVar
870−
871− -- echo server
872− forkIO $ do
873− localNode <- newLocalNode transport initRemoteTable
874− echoServer <- forkProcess localNode $ forever $ do
875− receiveWait [
876− matchAnyIf (\(_ :: ProcessId, (s :: String)) -> s /= "bar")
877− tryHandleMessage
878− ]
879− putMVar echoAddr echoServer
880−
881− -- Client
882− forkIO $ do
883− localNode <- newLocalNode transport initRemoteTable
884− server <- readMVar echoAddr
885−
886− runProcess localNode $ do
887− pid <- getSelfPid
888− send server (pid, "foo")
889− "foo" <- expect
890− send server (pid, "baz")
891− "baz" <- expect
892− send server (pid, "bar")
893− Nothing <- (expectTimeout 100000) :: Process (Maybe Double)
894− liftIO $ putMVar clientDone ()
895−
896− takeMVar clientDone
897− where tryHandleMessage :: Message -> Process (Maybe ())
898− tryHandleMessage msg =
899− handleMessage msg (\(pid :: ProcessId, (m :: String))
900− -> do { send pid m; return () })
901−
902−testMatchMessageWithUnwrap :: NT.Transport -> Assertion
903−testMatchMessageWithUnwrap transport = do
904− echoAddr <- newEmptyMVar
905− clientDone <- newEmptyMVar
906−
907− -- echo server
908− forkIO $ do
909− localNode <- newLocalNode transport initRemoteTable
910− echoServer <- forkProcess localNode $ forever $ do
911− msg <- receiveWait [
912− matchMessage (\(m :: Message) -> do
913− return m)
914− ]
915− unwrapped <- unwrapMessage msg :: Process (Maybe (ProcessId, Message))
916− case unwrapped of
917− (Just (p, msg')) -> forward msg' p
918− Nothing -> die "unable to unwrap the message"
919− putMVar echoAddr echoServer
920−
921− -- Client
922− forkIO $ do
923− localNode <- newLocalNode transport initRemoteTable
924− server <- readMVar echoAddr
925−
926− runProcess localNode $ do
927− pid <- getSelfPid
928− send server (pid, wrapMessage ("foo" :: String))
929− "foo" <- expect
930− send server (pid, wrapMessage ("baz" :: String))
931− "baz" <- expect
932− liftIO $ putMVar clientDone ()
933−
934− takeMVar clientDone
935−
936−-- Test 'receiveChanTimeout'
937−testReceiveChanTimeout :: NT.Transport -> Assertion
938−testReceiveChanTimeout transport = do
939− done <- newEmptyMVar
940− sendPort <- newEmptyMVar
941−
942− forkTry $ do
943− localNode <- newLocalNode transport initRemoteTable
944− runProcess localNode $ do
945− -- Create a typed channel
946− (sp, rp) <- newChan :: Process (SendPort Bool, ReceivePort Bool)
947− liftIO $ putMVar sendPort sp
948−
949− -- Wait for a message with a delay. No message arrives, we should get Nothing after 1 second
950− Nothing <- receiveChanTimeout 1000000 rp
951−
952− -- Wait for a message with a delay again. Now a message arrives after 0.5 seconds
953− Just True <- receiveChanTimeout 1000000 rp
954−
955− -- Wait for a message with zero timeout: non-blocking check. No message is available, we get Nothing
956− Nothing <- receiveChanTimeout 0 rp
957−
958− -- Again, but now there is a message available
959− liftIO $ threadDelay 1000000
960− Just False <- receiveChanTimeout 0 rp
961−
962− liftIO $ putMVar done ()
963−
964− forkTry $ do
965− localNode <- newLocalNode transport initRemoteTable
966− runProcess localNode $ do
967− sp <- liftIO $ readMVar sendPort
968−
969− liftIO $ threadDelay 1500000
970− sendChan sp True
971−
972− liftIO $ threadDelay 500000
973− sendChan sp False
974−
975− takeMVar done
976−
977−-- | Test Functor, Applicative, Alternative and Monad instances for ReceiveChan
978−testReceiveChanFeatures :: NT.Transport -> Assertion
979−testReceiveChanFeatures transport = do
980− done <- newEmptyMVar
981−
982− forkTry $ do
983− localNode <- newLocalNode transport initRemoteTable
984− runProcess localNode $ do
985− (spInt, rpInt) <- newChan :: Process (SendPort Int, ReceivePort Int)
986− (spBool, rpBool) <- newChan :: Process (SendPort Bool, ReceivePort Bool)
987−
988− -- Test Functor instance
989−
990− sendChan spInt 2
991− sendChan spBool False
992−
993− rp1 <- mergePortsBiased [even <$> rpInt, rpBool]
994−
995− True <- receiveChan rp1
996− False <- receiveChan rp1
997−
998− -- Test Applicative instance
999−
1000− sendChan spInt 3
1001− sendChan spInt 4
1002−
1003− let rp2 = pure (+) <*> rpInt <*> rpInt
1004−
1005− 7 <- receiveChan rp2
1006−
1007− -- Test Alternative instance
1008−
1009− sendChan spInt 3
1010− sendChan spBool True
1011−
1012− let rp3 = (even <$> rpInt) <|> rpBool
1013−
1014− False <- receiveChan rp3
1015− True <- receiveChan rp3
1016−
1017− -- Test Monad instance
1018−
1019− sendChan spBool True
1020− sendChan spBool False
1021− sendChan spInt 5
1022−
1023− let rp4 :: ReceivePort Int
1024− rp4 = do b <- rpBool
1025− if b
1026− then rpInt
1027− else return 7
1028−
1029− 5 <- receiveChan rp4
1030− 7 <- receiveChan rp4
1031−
1032− liftIO $ putMVar done ()
1033−
1034− takeMVar done
1035−
1036−testKillLocal :: NT.Transport -> Assertion
1037−testKillLocal transport = do
1038− localNode <- newLocalNode transport initRemoteTable
1039− done <- newEmptyMVar
1040−
1041− pid <- forkProcess localNode $ do
1042− liftIO $ threadDelay 1000000
1043−
1044− runProcess localNode $ do
1045− ref <- monitor pid
1046− us <- getSelfPid
1047− kill pid "TestKill"
1048− ProcessMonitorNotification ref' pid' (DiedException ex) <- expect
1049− True <- return $ ref == ref' && pid == pid' && ex == "killed-by=" ++ show us ++ ",reason=TestKill"
1050− liftIO $ putMVar done ()
1051−
1052− takeMVar done
1053−
1054−testKillRemote :: NT.Transport -> Assertion
1055−testKillRemote transport = do
1056− node1 <- newLocalNode transport initRemoteTable
1057− node2 <- newLocalNode transport initRemoteTable
1058− done <- newEmptyMVar
1059−
1060− pid <- forkProcess node1 $ do
1061− liftIO $ threadDelay 1000000
1062−
1063− runProcess node2 $ do
1064− ref <- monitor pid
1065− us <- getSelfPid
1066− kill pid "TestKill"
1067− ProcessMonitorNotification ref' pid' (DiedException reason) <- expect
1068− True <- return $ ref == ref' && pid == pid' && reason == "killed-by=" ++ show us ++ ",reason=TestKill"
1069− liftIO $ putMVar done ()
1070−
1071− takeMVar done
1072−
1073−testCatchesExit :: NT.Transport -> Assertion
1074−testCatchesExit transport = do
1075− localNode <- newLocalNode transport initRemoteTable
1076− done <- newEmptyMVar
1077−
1078− _ <- forkProcess localNode $ do
1079− (die ("foobar", 123 :: Int))
1080− `catchesExit` [
1081− (\_ m -> handleMessage m (\(_ :: String) -> return ()))
1082− , (\_ m -> handleMessage m (\(_ :: Maybe Int) -> return ()))
1083− , (\_ m -> handleMessage m (\(_ :: String, _ :: Int)
1084− -> (liftIO $ putMVar done ()) >> return ()))
1085− ]
1086−
1087− takeMVar done
1088−
1089−testHandleMessageIf :: NT.Transport -> Assertion
1090−testHandleMessageIf transport = do
1091− localNode <- newLocalNode transport initRemoteTable
1092− done <- newEmptyMVar
1093− _ <- forkProcess localNode $ do
1094− self <- getSelfPid
1095− send self (5 :: Integer, 10 :: Integer)
1096− msg <- receiveWait [ matchMessage return ]
1097− Nothing <- handleMessageIf msg (\() -> True) (\() -> die $ "whoops")
1098− handleMessageIf msg (\(x :: Integer, y :: Integer) -> x == 5 && y == 10)
1099− (\input -> liftIO $ putMVar done input)
1100− return ()
1101−
1102− result <- takeMVar done
1103− expectThat result $ equalTo (5, 10)
1104−
1105−testCatches :: NT.Transport -> Assertion
1106−testCatches transport = do
1107− localNode <- newLocalNode transport initRemoteTable
1108− done <- newEmptyMVar
1109−
1110− _ <- forkProcess localNode $ do
1111− node <- getSelfNode
1112− (liftIO $ throwIO (ProcessLinkException (nullProcessId node) DiedNormal))
1113− `catches` [
1114− Handler (\(ProcessLinkException _ _) -> liftIO $ putMVar done ())
1115− ]
1116−
1117− takeMVar done
1118−
1119−testMaskRestoreScope :: NT.Transport -> Assertion
1120−testMaskRestoreScope transport = do
1121− localNode <- newLocalNode transport initRemoteTable
1122− parentPid <- newEmptyMVar :: IO (MVar ProcessId)
1123− spawnedPid <- newEmptyMVar :: IO (MVar ProcessId)
1124−
1125− void $ runProcess localNode $ mask $ \unmask -> do
1126− getSelfPid >>= liftIO . putMVar parentPid
1127− void $ spawnLocal $ unmask (getSelfPid >>= liftIO . putMVar spawnedPid)
1128−
1129− parent <- liftIO $ takeMVar parentPid
1130− child <- liftIO $ takeMVar spawnedPid
1131− expectThat parent $ isNot $ equalTo child
1132−
1133−testDie :: NT.Transport -> Assertion
1134−testDie transport = do
1135− localNode <- newLocalNode transport initRemoteTable
1136− done <- newEmptyMVar
1137−
1138− _ <- forkProcess localNode $ do
1139− (die ("foobar", 123 :: Int))
1140− `catchExit` \_from reason -> do
1141− -- TODO: should verify that 'from' has the right value
1142− True <- return $ reason == ("foobar", 123 :: Int)
1143− liftIO $ putMVar done ()
1144−
1145− takeMVar done
1146−
1147−testPrettyExit :: NT.Transport -> Assertion
1148−testPrettyExit transport = do
1149− localNode <- newLocalNode transport initRemoteTable
1150− done <- newEmptyMVar
1151−
1152− _ <- forkProcess localNode $ do
1153− (die "timeout")
1154− `catch` \ex@(ProcessExitException from _) ->
1155− let expected = "exit-from=" ++ (show from)
1156− in do
1157− True <- return $ (show ex) == expected
1158− liftIO $ putMVar done ()
1159−
1160− takeMVar done
1161−
1162−testExitLocal :: NT.Transport -> Assertion
1163−testExitLocal transport = do
1164− localNode <- newLocalNode transport initRemoteTable
1165− supervisedDone <- newEmptyMVar
1166− supervisorDone <- newEmptyMVar
1167−
1168− pid <- forkProcess localNode $ do
1169− (liftIO $ threadDelay 100000)
1170− `catchExit` \_from reason -> do
1171− -- TODO: should verify that 'from' has the right value
1172− True <- return $ reason == "TestExit"
1173− liftIO $ putMVar supervisedDone ()
1174−
1175− runProcess localNode $ do
1176− ref <- monitor pid
1177− exit pid "TestExit"
1178− -- This time the client catches the exception, so it dies normally
1179− ProcessMonitorNotification ref' pid' DiedNormal <- expect
1180− True <- return $ ref == ref' && pid == pid'
1181− liftIO $ putMVar supervisorDone ()
1182−
1183− takeMVar supervisedDone
1184− takeMVar supervisorDone
1185−
1186−testExitRemote :: NT.Transport -> Assertion
1187−testExitRemote transport = do
1188− node1 <- newLocalNode transport initRemoteTable
1189− node2 <- newLocalNode transport initRemoteTable
1190− supervisedDone <- newEmptyMVar
1191− supervisorDone <- newEmptyMVar
1192−
1193− pid <- forkProcess node1 $ do
1194− (liftIO $ threadDelay 100000)
1195− `catchExit` \_from reason -> do
1196− -- TODO: should verify that 'from' has the right value
1197− True <- return $ reason == "TestExit"
1198− liftIO $ putMVar supervisedDone ()
1199−
1200− runProcess node2 $ do
1201− ref <- monitor pid
1202− exit pid "TestExit"
1203− ProcessMonitorNotification ref' pid' DiedNormal <- expect
1204− True <- return $ ref == ref' && pid == pid'
1205− liftIO $ putMVar supervisorDone ()
1206−
1207− takeMVar supervisedDone
1208− takeMVar supervisorDone
1209−
1210−testUnsafeSend :: NT.Transport -> Assertion
1211−testUnsafeSend transport = do
1212− serverAddr <- newEmptyMVar
1213− clientDone <- newEmptyMVar
1214−
1215− localNode <- newLocalNode transport initRemoteTable
1216− void $ forkProcess localNode $ do
1217− self <- getSelfPid
1218− liftIO $ putMVar serverAddr self
1219− clientAddr <- expect
1220− unsafeSend clientAddr ()
1221−
1222− void $ forkProcess localNode $ do
1223− serverPid <- liftIO $ takeMVar serverAddr
1224− getSelfPid >>= unsafeSend serverPid
1225− () <- expect
1226− liftIO $ putMVar clientDone ()
1227−
1228− takeMVar clientDone
1229−
1230−testUnsafeNSend :: NT.Transport -> Assertion
1231−testUnsafeNSend transport = do
1232− clientDone <- newEmptyMVar
1233−
1234− localNode <- newLocalNode transport initRemoteTable
1235−
1236− pid <- forkProcess localNode $ do
1237− () <- expect
1238− liftIO $ putMVar clientDone ()
1239−
1240− void $ runProcess localNode $ do
1241− register "foobar" pid
1242− unsafeNSend "foobar" ()
1243−
1244− takeMVar clientDone
1245−
1246−testUnsafeSendChan :: NT.Transport -> Assertion
1247−testUnsafeSendChan transport = do
1248− serverAddr <- newEmptyMVar
1249− clientDone <- newEmptyMVar
1250−
1251− localNode <- newLocalNode transport initRemoteTable
1252− void $ forkProcess localNode $ do
1253− self <- getSelfPid
1254− liftIO $ putMVar serverAddr self
1255− sp <- expect
1256− unsafeSendChan sp ()
1257−
1258− void $ forkProcess localNode $ do
1259− serverPid <- liftIO $ takeMVar serverAddr
1260− (sp, rp) <- newChan
1261− unsafeSend serverPid sp
1262− () <- receiveChan rp
1263− liftIO $ putMVar clientDone ()
1264−
1265− takeMVar clientDone
1266−
1267−tests :: (NT.Transport, TransportInternals) -> [Test]
1268−tests (transport, transportInternals) = [
1269− testGroup "Basic features" [
1270− testCase "Ping" (testPing transport)
1271− , testCase "Math" (testMath transport)
1272− , testCase "Timeout" (testTimeout transport)
1273− , testCase "Timeout0" (testTimeout0 transport)
1274− , testCase "SendToTerminated" (testSendToTerminated transport)
1275− , testCase "TypedChannnels" (testTypedChannels transport)
1276− , testCase "MergeChannels" (testMergeChannels transport)
1277− , testCase "Terminate" (testTerminate transport)
1278− , testCase "Registry" (testRegistry transport)
1279− , testCase "RemoteRegistry" (testRemoteRegistry transport)
1280− , testCase "SpawnLocal" (testSpawnLocal transport)
1281− , testCase "HandleMessageIf" (testHandleMessageIf transport)
1282− , testCase "MatchAny" (testMatchAny transport)
1283− , testCase "MatchAnyHandle" (testMatchAnyHandle transport)
1284− , testCase "MatchAnyNoHandle" (testMatchAnyNoHandle transport)
1285− , testCase "MatchAnyIf" (testMatchAnyIf transport)
1286− , testCase "MatchMessageUnwrap" (testMatchMessageWithUnwrap transport)
1287− , testCase "ReceiveChanTimeout" (testReceiveChanTimeout transport)
1288− , testCase "ReceiveChanFeatures" (testReceiveChanFeatures transport)
1289− , testCase "KillLocal" (testKillLocal transport)
1290− , testCase "KillRemote" (testKillRemote transport)
1291− , testCase "Die" (testDie transport)
1292− , testCase "PrettyExit" (testPrettyExit transport)
1293− , testCase "CatchesExit" (testCatchesExit transport)
1294− , testCase "Catches" (testCatches transport)
1295− , testCase "MaskRestoreScope" (testMaskRestoreScope transport)
1296− , testCase "ExitLocal" (testExitLocal transport)
1297− , testCase "ExitRemote" (testExitRemote transport)
1298− -- Unsafe Primitives
1299− , testCase "TestUnsafeSend" (testUnsafeSend transport)
1300− , testCase "TestUnsafeNSend" (testUnsafeNSend transport)
1301− , testCase "TestUnsafeSendChan" (testUnsafeSendChan transport)
1302− ]
1303− , testGroup "Monitoring and Linking" [
1304− -- Monitoring processes
1305− --
1306− -- The "missing" combinations in the list below don't make much sense, as
1307− -- we cannot guarantee that the monitor reply or link exception will not
1308− -- happen before the unmonitor or unlink
1309− testCase "MonitorUnreachable" (testMonitorUnreachable transport True False)
1310− , testCase "MonitorNormalTermination" (testMonitorNormalTermination transport True False)
1311− , testCase "MonitorAbnormalTermination" (testMonitorAbnormalTermination transport True False)
1312− , testCase "MonitorLocalDeadProcess" (testMonitorLocalDeadProcess transport True False)
1313− , testCase "MonitorRemoteDeadProcess" (testMonitorRemoteDeadProcess transport True False)
1314− , testCase "MonitorDisconnect" (testMonitorDisconnect transport True False)
1315− , testCase "LinkUnreachable" (testMonitorUnreachable transport False False)
1316− , testCase "LinkNormalTermination" (testMonitorNormalTermination transport False False)
1317− , testCase "LinkAbnormalTermination" (testMonitorAbnormalTermination transport False False)
1318− , testCase "LinkLocalDeadProcess" (testMonitorLocalDeadProcess transport False False)
1319− , testCase "LinkRemoteDeadProcess" (testMonitorRemoteDeadProcess transport False False)
1320− , testCase "LinkDisconnect" (testMonitorDisconnect transport False False)
1321− , testCase "UnmonitorNormalTermination" (testMonitorNormalTermination transport True True)
1322− , testCase "UnmonitorAbnormalTermination" (testMonitorAbnormalTermination transport True True)
1323− , testCase "UnmonitorDisconnect" (testMonitorDisconnect transport True True)
1324− , testCase "UnlinkNormalTermination" (testMonitorNormalTermination transport False True)
1325− , testCase "UnlinkAbnormalTermination" (testMonitorAbnormalTermination transport False True)
1326− , testCase "UnlinkDisconnect" (testMonitorDisconnect transport False True)
1327− -- Monitoring nodes and channels
1328− , testCase "MonitorNode" (testMonitorNode transport)
1329− , testCase "MonitorLiveNode" (testMonitorLiveNode transport)
1330− , testCase "MonitorChannel" (testMonitorChannel transport)
1331− -- Reconnect
1332− , testCase "Reconnect" (testReconnect transport transportInternals)
1333− ]
1334− ]
1335−
1336−main :: IO ()
1337−main = do
1338− Right transport <- createTransportExposeInternals "127.0.0.1" "8080" defaultTCPParameters
1339− defaultMain (tests transport)