cci-0.3.1: test/test_cci.hs
--
-- Copyright (C) 2012 Parallel Scientific. All rights reserved.
--
-- See the accompanying LICENSE file for license information.
--
--
-- This file implements an executable which runs automatically
-- generated tests for the CCI haskell bindings.
--
import Control.Monad ( when )
import qualified Data.Map as M( empty, insert, lookup )
import GHC.Exts ( groupWith )
import System.Exit ( exitFailure )
import TestGen ( testProp, defaultTestConfig, runCommands, Command(..), Msg(..)
, ProcCommand, Response(..), TestConfig(..), generateCTest )
import Network.CCI ( Status(..) )
import System.Console.CmdArgs
main :: IO ()
main = props
props :: IO ()
props = do
tc <- cmdArgs (TestConfig { nSends= intopt "Amount of messages sent per interaction" (nSends defaultTestConfig)
, nTries= intopt "Amount of command sequences to generate" (nTries defaultTestConfig)
, nProcesses= intopt "Amount of processes to test" (nProcesses defaultTestConfig)
, nMinMsgLen= intopt "Minimum size of messages to test" (nMinMsgLen defaultTestConfig)
, nMaxMsgLen= intopt "Maximum size of messages to test" (nMaxMsgLen defaultTestConfig)
, nPerProcessInteractions=
intopt "Amount of interactions each process initiates during a test" (nPerProcessInteractions defaultTestConfig)
&= name "nPerProcRuns" &= explicit
, nErrors= intopt "Amount of errors to collect before stopping testing" (nErrors defaultTestConfig)
, withValgrind = boolopt "Run tests with valgrind" (withValgrind defaultTestConfig) &= name "with-valgrind" &= explicit
, testRMA = boolopt "Test rma operations" (testRMA defaultTestConfig) &= name "test-rma" &= explicit
}
&= summary "CCI test generator v0.0.1, (C) Parallel Scientific 2012"
&= details ["See test/README for details."]
&= program "test_cci"
)
errs <- testProp tc printErrorAndGenerateTest$ \cmds rs ->
[ ( "sends equal completions"
, testRMA tc || length (filter (isSendCommand . snd) cmds) == length (concatMap (filter isSendCompletion) rs)
)
, ( "messages arrive sorted"
, testRMA tc || matchSendRecvs (collectSends cmds) (collectRecvs rs)
)
]
when (not (null errs))$ exitFailure
where
isSendCompletion (SendCompletion _ mid _) = mid>0
isSendCompletion _ = False
intopt :: (Default a,Data a,Show a) => String -> a -> a
intopt s i = i &= help (s++" [default: "++show i++"]") &= opt i
boolopt :: (Default a,Data a,Show a) => String -> a -> a
boolopt s i = i &= help (s++" [default: "++show i++"]")
printErrorAndGenerateTest e@(s,_,_) i = do
print e
let cfilename :: Int -> String
cfilename i = "t"++show i++".c"
writeFile (cfilename i)$ generateCTest s
putStrLn$ "A test program has been written to " ++ show (cfilename i)
isSendCommand :: Command -> Bool
isSendCommand (Send _ _ _) = True
isSendCommand _ = False
collectSends :: [ProcCommand] -> [(Int,[[Command]])]
collectSends = map toPair'
. groupWith fst
. map toPair
. groupWith destinationAndConnection
. filter (isSendCommand . snd . snd)
. attachProcDestination
where
destinationAndConnection (i,(_,Send cid _ _)) = (i,cid)
destinationAndConnection _ = error "Props.destinationAndConnection: unexpected value"
toPair ls@((Just i,_):_) = (i,map (snd . snd) ls)
toPair _ = error "Props.collectSends: unexpected value"
toPair' ls@((i,_):_) = (i,map snd ls)
toPair' _ = error "Props.collectSends toPair': unexpected value"
attachProcDestination :: [ProcCommand] -> [(Maybe Int,ProcCommand)]
attachProcDestination = go M.empty
where go m (c@(tprocs,ConnectTo _ pid cid _):cms) =
(Nothing,c) : go (M.insert cid (pid,tprocs) m) cms
go m (c@(tprocs,Send cid _ _):cms) =
( fmap (\(pid,tps) -> if elem pid tprocs then head tps else pid)
$ M.lookup cid m
, c
) : go m cms
go m (c:cms) = (Nothing,c) : go m cms
go _ [] = []
collectRecvs :: [[Response]] -> [[[Response]]]
collectRecvs = map (groupWith getConn) . map (filter isRecvResp)
where
isRecvResp (Recv _ (Msg _ _)) = True
isRecvResp _ = False
getConn (Recv cid _) = cid
getConn _ = error "Props.collectRecvs: unexpected value."
matchSendRecvs :: [(Int,[[Command]])] -> [[[Response]]] -> Bool
matchSendRecvs [] _ = True
matchSendRecvs ((i,ss):cms) rs = match' ss (rs!!i) && matchSendRecvs cms rs
where match' ss' rs' = length ss' == length rs' && and (zipWith match'' ss' rs')
match'' ss'' rs'' = length ss'' == length rs'' && and (zipWith matchCR ss'' rs'')
matchCR (Send cid _ msg) (Recv cid' msg') = cid == cid' && msg == msg'
matchCR _ _ = error "Props.matchSendRecvs: unexpected values"
singleTest :: IO ()
singleTest = runCommands test2 >>= print
test :: [ProcCommand]
test = [([0],Accept 5),([1],ConnectTo "" 0 5 Nothing),([1,0],WaitConnection 5),([1],Send 5 1 (Msg 1 185)),([0],WaitRecv 5 1),([1],Send 5 2 (Msg 2 969)),([1],WaitSendCompletion 5 1),([1],WaitSendCompletion 5 2),([1],Send 5 3 (Msg 3 495)),([1],WaitSendCompletion 5 3),([0],WaitRecv 5 2),([0],WaitRecv 5 3),([1],Disconnect 5)]
testR :: [[Response]]
testR = [[ReqAccepted 5,ConnectAccepted 5,Recv 5 (Msg 0 185),Recv 5 (Msg 2 495),Recv 5 (Msg 1 969)],[ConnectAccepted 5,SendCompletion 5 0 SUCCESS,SendCompletion 5 1 SUCCESS,SendCompletion 5 2 SUCCESS]]
test2 :: [ProcCommand]
test2 = []