1{-# LANGUAGE DeriveGeneric #-}
2module Control.Distributed.Process.Tests.Mx (tests) where
4import Control.Distributed.Process.Tests.Internal.Utils
5import Network.Transport.Test (TestTransport(..))
7import Control.Concurrent (threadDelay)
8import Control.Distributed.Process
9import Control.Distributed.Process.Node
10import Control.Distributed.Process.Management
31import Control.Monad (void)
33import Data.List (find, sort)
34import Data.Maybe (isJust)
37#if ! MIN_VERSION_base(4,6,0)
38import Prelude hiding (catch, log)
45import Test.Framework.Providers.HUnit (testCase)
48 deriving (Typeable, Generic, Eq)
50instance Binary Publish where
52testAgentBroadcast :: TestResult () -> Process ()
53testAgentBroadcast result = do
54 (resultSP, resultRP) <- newChan :: Process (SendPort (), ReceivePort ())
56 publisher <- mxAgent (MxAgentId "publisher-agent") () [
57 mxSink $ \() -> mxBroadcast Publish >> mxReady
60 consumer <- mxAgent (MxAgentId "consumer-agent") () [
61 mxSink $ \Publish -> (liftMX $ sendChan resultSP ()) >> mxReady
65 -- Once the publisher has seen our message, it will broadcast the Publish
66 -- and the consumer will see that and send the result to our typed channel.
67 stash result =<< receiveChan resultRP
69 kill publisher "finished"
70 kill consumer "finished"
72testAgentDualInput :: TestResult (Maybe Int) -> Process ()
73testAgentDualInput result = do
75 _ <- mxAgent (MxAgentId "sum-agent") (0 :: Int) [
76 mxSink $ (\(i :: Int) -> do
77 mxSetLocal . (+i) =<< mxGetLocal
80 then do mxGetLocal >>= liftMX . sendChan sp
81 mxDeactivate "finished"
86 nsend "sum-agent" (3 :: Int)
88 nsend "sum-agent" (4 :: Int)
91 stash result =<< receiveChanTimeout 10000000 rp
93testAgentPrioritisation :: TestResult [String] -> Process ()
94testAgentPrioritisation result = do
96 -- TODO: this isn't really testing how we /prioritise/ one source
97 -- over another at all, but I've not yet figured out the right way
98 -- to do so, since we're at the whim of the scheduler with regards
99 -- the timeliness of nsend versus mxNotify anyway.
101 let name = "prioritising-agent"
103 void $ mxAgent (MxAgentId name) ["first"] [
104 mxSink (\(s :: String) -> do
108 n | n == 5 -> do liftMX $ sendChan sp st
109 mxDeactivate "finished"
110 _ -> mxReceive -- go to the mailbox
119 stash result . sort =<< receiveChan rp
121testAgentMailboxHandling :: TestResult (Maybe ()) -> Process ()
122testAgentMailboxHandling result = do
124 agent <- mxAgent (MxAgentId "listener-agent") () [
125 mxSink $ \() -> (liftMX $ sendChan sp ()) >> mxReady
128 nsend "listener-agent" ()
130 stash result =<< receiveChanTimeout 1000000 rp
131 kill agent "finished"
133testAgentEventHandling :: TestResult Bool -> Process ()
134testAgentEventHandling result = do
135 let initState = [] :: [MxEvent]
136 agentPid <- mxAgent (MxAgentId "lifecycle-listener-agent") initState [
141 (MxSpawned _) -> mxSetLocal (ev:st)
142 (MxProcessDied _ _) -> mxSetLocal (ev:st)
145 (mxSink $ \(ev, sp :: SendPort Bool) -> do
150 isJust $ find (\ev' ->
152 (MxSpawned p') -> p' == p
155 isJust $ find (\ev' ->
157 (MxProcessDied p' r') -> p' == p && r == r'
160 liftMX $ sendChan sp found
164 _ <- monitor agentPid
166 pid <- spawnLocal $ sendChan sp ()
169 -- By waiting for a monitor notification, we have a
170 -- higher probably that the agent has seen
172 receiveWait [ match (\(ProcessMonitorNotification _ _ _) -> return ()) ]
174 (replyTo, reply) <- newChan :: Process (SendPort Bool, ReceivePort Bool)
175 mxNotify (MxSpawned pid, replyTo)
176 mxNotify (MxProcessDied pid DiedNormal, replyTo)
178 seenAlive <- receiveChan reply
179 seenDead <- receiveChan reply
181 stash result $ seenAlive && seenDead
183testAgentPublication :: TestResult (Maybe Publish) -> Process ()
184testAgentPublication result = do
185 (syncChan, rp) <- newChan
186 let ourId = MxAgentId "publication-agent"
187 agentPid <- mxAgent ourId () [
190 liftMX $ mxSet selfId "publish" Publish >> sendChan syncChan ()
197 stash result =<< mxGet ourId "publish"
199 mref <- monitor agentPid
200 kill agentPid "finished"
202 matchIf (\(ProcessMonitorNotification ref _ _) -> ref == mref)
206testAgentTableClear :: Int -> TestResult (Maybe Int, Maybe Int) -> Process ()
207testAgentTableClear val result =
208 let tId = (MxAgentId "agent-1")
211 get1 <- mxGet tId tKey
213 get2 <- mxGet tId tKey
214 stash result (get1, get2)
216testAgentTablePurge :: TestResult (Maybe Int) -> Process ()
217testAgentTablePurge result =
218 let tId = MxAgentId "agent-2"
220 mxSet tId tKey (12345 :: Int)
222 stash result =<< mxGet tId tKey
224testAgentTableDelete :: Int
225 -> TestResult (Maybe Int, Maybe Int, Maybe Int)
227testAgentTableDelete val result =
228 let tId = (MxAgentId "agent-3")
231 get1 <- mxGet tId tKey
233 get2 <- mxGet tId tKey
235 get3 <- mxGet tId tKey
236 stash result (get1, get2, get3)
238tests :: TestTransport -> IO [Test]
239tests TestTransport{..} = do
240 node1 <- newLocalNode testTransport initRemoteTable
242 testGroup "Mx Agents" [
243 testCase "Event Handling"
245 "expected True, but events where not as expected"
246 node1 True testAgentEventHandling)
247 , testCase "Inter-Agent Broadcast"
249 "expected (), but no broadcast was received"
250 node1 () testAgentBroadcast)
251 , testCase "Agent Mailbox Handling"
253 "expected (Just ()), but no regular (mailbox) input was handled"
254 node1 (Just ()) testAgentMailboxHandling)
255 , testCase "Agent Dual Input Handling"
257 "expected sum = 15, but the result was Nothing"
258 node1 (Just 15 :: Maybe Int) testAgentDualInput)
259 , testCase "Agent Input Prioritisation"
261 "expected [first, second, third, fourth, fifth], but result diverged"
262 node1 (sort ["first", "second",
264 "fifth"]) testAgentPrioritisation)
266 testGroup "Mx Global Properties" [
267 testCase "Global Property Publication"
269 "expected (Just Publish), but no table entry was found"
270 node1 (Just Publish) testAgentPublication)
271 , testCase "Clearing Global Properties"
273 "expected (Just 1024, Nothing): invalid table entry found!"
274 node1 (Just 1024, Nothing) (testAgentTableClear 1024))
275 , testCase "Purging Global Tables"
277 "expected Nothing, but a table entry was found"
278 node1 Nothing testAgentTablePurge)
279 , testCase "Deleting and (Re)Creating Global Tables"
281 "expected (Just 15, Nothing, Just 15): invalid table entry found!"
282 node1 (Just 15, Nothing, Just 15) (testAgentTableDelete 15))
283 -- Wait for other tests to finish.
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list