@@ -1,11 +1,7 @@
1+{-# LANGUAGE DeriveGeneric #-}
1module Main where
2module Main where
3import Control.Concurrent (threadDelay)
4import Control.Concurrent (threadDelay)
4−import Control.Concurrent.MVar
9import Control.Distributed.Process
5import Control.Distributed.Process
10import Control.Distributed.Process.Management
6import Control.Distributed.Process.Management
11 ( MxEvent(..)
7 ( MxEvent(..)
@@ -13,18 +9,27 @@ import Control.Distributed.Process.Management
17 , mxGetLocal
13 , mxGetLocal
18 , mxSetLocal
14 , mxSetLocal
19 , mxNotify
15 , mxNotify
21import Control.Distributed.Process.Node
24import Control.Distributed.Process.Node
22 ( LocalNode
25 ( LocalNode
24import Data.List (find)
28import Data.List (find)
25import Data.Maybe (isJust)
29import Data.Maybe (isJust)
26import qualified Network.Transport as NT
32import qualified Network.Transport as NT
28#if ! MIN_VERSION_base(4,6,0)
33#if ! MIN_VERSION_base(4,6,0)
29import Prelude hiding (catch, log)
34import Prelude hiding (catch, log)
@@ -36,41 +41,71 @@ import Test.Framework
36import Test.Framework.Providers.HUnit (testCase)
41import Test.Framework.Providers.HUnit (testCase)
37import TestUtils
42import TestUtils
44+data Publish = Publish
45+ deriving (Typeable, Generic, Eq)
47+instance Binary Publish where
49+testAgentBroadcast :: TestResult (Maybe ()) -> Process ()
50+testAgentBroadcast result = do
51+ (resultSP, resultRP) <- newChan :: Process (SendPort (), ReceivePort ())
53+ publisher <- mxAgent (MxAgentId "publisher-agent") () [
54+ mxSink $ \() -> mxBroadcast Publish >> mxReady
57+ consumer <- mxAgent (MxAgentId "consumer-agent") () [
58+ mxSink $ \Publish -> (liftMX $ sendChan resultSP ()) >> mxReady
62+ -- once the publisher has seen our message, it will broadcast the Publish
63+ stash result =<< receiveChanTimeout 1000000 resultRP
65+ kill publisher "finished"
66+ kill consumer "finished"
39testAgentEventHandling :: TestResult Bool -> Process ()
68testAgentEventHandling :: TestResult Bool -> Process ()
40testAgentEventHandling result = do
69testAgentEventHandling result = do
41 let initState = [] :: [MxEvent]
70 let initState = [] :: [MxEvent]
42− agentPid <- mxAgent (MxAgentId "lifecycle-listener-agent") initState [
71+ agentPid <- mxAgent (MxAgentId "lifecycle-listener-agent") initState [
43 (mxSink $ \ev -> do
72 (mxSink $ \ev -> do
44 st <- mxGetLocal
73 st <- mxGetLocal
45− let act = case ev of
75+ case ev of
46− (MxSpawned _) -> mxSetLocal (ev:st)
76+ (MxSpawned _) -> mxSetLocal (ev:st)
47− (MxProcessDied _ _) -> mxSetLocal (ev:st)
77+ (MxProcessDied _ _) -> mxSetLocal (ev:st)
48− _ -> return ()
78+ _ -> return ()
49 act >> mxReady),
79 act >> mxReady),
50 (mxSink $ \(ev, sp :: SendPort Bool) -> do
80 (mxSink $ \(ev, sp :: SendPort Bool) -> do
51 st <- mxGetLocal
81 st <- mxGetLocal
52− let found = case ev of
82+ let found =
53− MxSpawned p ->
84+ MxSpawned p ->
54− isJust $ find (\ev' ->
85+ isJust $ find (\ev' ->
55− case ev' of
86+ case ev' of
56− (MxSpawned p') -> p' == p
87+ (MxSpawned p') -> p' == p
57− _ -> False) st
88+ _ -> False) st
58− MxProcessDied p r ->
89+ MxProcessDied p r ->
59− isJust $ find (\ev' ->
90+ isJust $ find (\ev' ->
60− case ev' of
91+ case ev' of
61− (MxProcessDied p' r') -> p' == p && r == r'
92+ (MxProcessDied p' r') -> p' == p && r == r'
62− _ -> False) st
93+ _ -> False) st
63− _ -> False
94+ _ -> False
64− mxLift $ sendChan sp found
95+ liftMX $ sendChan sp found
65− liftIO $ putStrLn $ "replied to " ++ (show sp)
69− mref <- monitor agentPid
99+ _ <- monitor agentPid
70 (sp, rp) <- newChan
100 (sp, rp) <- newChan
71 pid <- spawnLocal $ sendChan sp ()
101 pid <- spawnLocal $ sendChan sp ()
72 () <- receiveChan rp
102 () <- receiveChan rp
104+ -- By waiting for a monitor notification, we have a
105+ -- higher probably that the agent has seen
107+ receiveWait [ match (\(ProcessMonitorNotification _ _ _) -> return ()) ]
74 (replyTo, reply) <- newChan :: Process (SendPort Bool, ReceivePort Bool)
109 (replyTo, reply) <- newChan :: Process (SendPort Bool, ReceivePort Bool)
75 mxNotify (MxSpawned pid, replyTo)
110 mxNotify (MxSpawned pid, replyTo)
76 mxNotify (MxProcessDied pid DiedNormal, replyTo)
111 mxNotify (MxProcessDied pid DiedNormal, replyTo)
@@ -80,21 +115,92 @@ testAgentEventHandling result = do
81 stash result $ seenAlive && seenDead
116 stash result $ seenAlive && seenDead
118+testAgentPublication :: TestResult (Maybe Publish) -> Process ()
119+testAgentPublication result = do
120+ (syncChan, rp) <- newChan
121+ let ourId = MxAgentId "publication-agent"
122+ agentPid <- mxAgent ourId () [
125+ liftMX $ mxSet selfId "publish" Publish >> sendChan syncChan ()
130+ () <- receiveChan rp
132+ stash result =<< mxGet ourId "publish"
134+ mref <- monitor agentPid
83 kill agentPid "finished"
135 kill agentPid "finished"
84 receiveWait [
136 receiveWait [
85 matchIf (\(ProcessMonitorNotification ref _ _) -> ref == mref)
137 matchIf (\(ProcessMonitorNotification ref _ _) -> ref == mref)
86 ((\_ -> return ()))
138 ((\_ -> return ()))
141+testAgentTableClear :: Int -> TestResult (Maybe Int, Maybe Int) -> Process ()
142+testAgentTableClear val result =
143+ let tId = (MxAgentId "agent-1")
144+ tKey = "key-1" in do
146+ get1 <- mxGet tId tKey
148+ get2 <- mxGet tId tKey
149+ stash result (get1, get2)
151+testAgentTablePurge :: TestResult (Maybe Int) -> Process ()
152+testAgentTablePurge result =
153+ let tId = MxAgentId "agent-2"
154+ tKey = "key-2" in do
155+ mxSet tId tKey (12345 :: Int)
157+ stash result =<< mxGet tId tKey
159+testAgentTableDelete :: Int
160+ -> TestResult (Maybe Int, Maybe Int, Maybe Int)
162+testAgentTableDelete val result =
163+ let tId = (MxAgentId "agent-3")
164+ tKey = "key-3" in do
166+ get1 <- mxGet tId tKey
168+ get2 <- mxGet tId tKey
170+ get3 <- mxGet tId tKey
171+ stash result (get1, get2, get3)
89tests :: LocalNode -> IO [Test]
173tests :: LocalNode -> IO [Test]
90tests node1 = do
174tests node1 = do
92− testGroup "Basic Agent Handling" [
176+ testGroup "Mx Agents" [
93− testCase "testAgentEventHandling"
177+ testCase "Event Handling"
94 (delayedAssertion
178 (delayedAssertion
95− "expected "
179+ "expected True, but events where not as expected"
96 node1 True testAgentEventHandling)
180 node1 True testAgentEventHandling)
181+ , testCase "Inter-Agent Broadcast"
183+ "expected (Just ()), but no broadcast was received"
184+ node1 (Just ()) testAgentBroadcast)
186+ testGroup "Mx Global Properties" [
187+ testCase "Global Property Publication"
189+ "expected (Just Publish), but no table entry was found"
190+ node1 (Just Publish) testAgentPublication)
191+ , testCase "Clearing Global Properties"
193+ "expected (Just 1024, Nothing): invalid table entry found!"
194+ node1 (Just 1024, Nothing) (testAgentTableClear 1024))
195+ , testCase "Purging Global Tables"
197+ "expected Nothing, but a table entry was found"
198+ node1 Nothing testAgentTablePurge)
199+ , testCase "Deleting and (Re)Creating Global Tables"
201+ "expected (Just 15, Nothing, Just 15): invalid table entry found!"
202+ node1 (Just 15, Nothing, Just 15) (testAgentTableDelete 15))
99statsTests :: NT.Transport -> IO [Test]
205statsTests :: NT.Transport -> IO [Test]
100statsTests _ = do
206statsTests _ = do