51 |
51 |
) where
|
52 |
52 |
|
53 |
53 |
import Test.QuickCheck
|
|
54 |
import Test.QuickCheck.Monadic (assert, monadicIO, run)
|
54 |
55 |
import Text.Printf (printf)
|
55 |
56 |
import Data.List (intercalate, nub, isPrefixOf)
|
56 |
57 |
import Data.Maybe
|
... | ... | |
60 |
61 |
import qualified Text.JSON as J
|
61 |
62 |
import qualified Data.Map
|
62 |
63 |
import qualified Data.IntMap as IntMap
|
|
64 |
import Control.Concurrent (forkIO)
|
|
65 |
import Control.Exception (bracket, catchJust)
|
|
66 |
import System.Directory (getTemporaryDirectory, removeFile)
|
|
67 |
import System.IO (hClose, openTempFile)
|
|
68 |
import System.IO.Error (isEOFErrorType, ioeGetErrorType)
|
63 |
69 |
|
64 |
70 |
import qualified Ganeti.Confd as Confd
|
65 |
71 |
import qualified Ganeti.Config as Config
|
... | ... | |
287 |
293 |
x <- elements (['a'..'z'] ++ ['0'..'9'] ++ "_-")
|
288 |
294 |
return (DNSChar x)
|
289 |
295 |
|
|
296 |
instance Show DNSChar where
|
|
297 |
show = show . dnsGetChar
|
|
298 |
|
290 |
299 |
-- | Generates a single name component.
|
291 |
300 |
getName :: Gen String
|
292 |
301 |
getName = do
|
... | ... | |
1820 |
1829 |
prop_Luxi_CallEncoding op =
|
1821 |
1830 |
(Luxi.validateCall (Luxi.buildCall op) >>= Luxi.decodeCall) ==? Types.Ok op
|
1822 |
1831 |
|
|
1832 |
-- | Helper to a get a temporary file name.
|
|
1833 |
getTempFileName :: IO FilePath
|
|
1834 |
getTempFileName = do
|
|
1835 |
tempdir <- getTemporaryDirectory
|
|
1836 |
(fpath, handle) <- openTempFile tempdir "luxitest"
|
|
1837 |
_ <- hClose handle
|
|
1838 |
removeFile fpath
|
|
1839 |
return fpath
|
|
1840 |
|
|
1841 |
-- | Helper to execute recvMsg but return Nothing if we reach EOF.
|
|
1842 |
handleEOF :: (IO a) -> IO (Maybe a)
|
|
1843 |
handleEOF action =
|
|
1844 |
catchJust
|
|
1845 |
(\e -> if isEOFErrorType (ioeGetErrorType e) then Just () else Nothing)
|
|
1846 |
(liftM Just action)
|
|
1847 |
(\_ -> return Nothing)
|
|
1848 |
|
|
1849 |
-- | Server ping-pong helper.
|
|
1850 |
luxiServerPong :: Luxi.Client -> IO ()
|
|
1851 |
luxiServerPong c = do
|
|
1852 |
msg <- handleEOF (Luxi.recvMsg c)
|
|
1853 |
case msg of
|
|
1854 |
Nothing -> return ()
|
|
1855 |
Just m -> Luxi.sendMsg c m >> luxiServerPong c
|
|
1856 |
|
|
1857 |
-- | Client ping-pong helper.
|
|
1858 |
luxiClientPong :: Luxi.Client -> [String] -> IO [String]
|
|
1859 |
luxiClientPong c =
|
|
1860 |
mapM (\m -> Luxi.sendMsg c m >> Luxi.recvMsg c)
|
|
1861 |
|
|
1862 |
-- | Monadic check that, given a server socket, we can connect via a
|
|
1863 |
-- client to it, and that we can send a list of arbitrary messages and
|
|
1864 |
-- get back what we sent.
|
|
1865 |
prop_Luxi_ClientServer :: [[DNSChar]] -> Property
|
|
1866 |
prop_Luxi_ClientServer dnschars = monadicIO $ do
|
|
1867 |
let msgs = map (map dnsGetChar) dnschars
|
|
1868 |
fpath <- run $ getTempFileName
|
|
1869 |
-- we need to create the server first, otherwise (if we do it in the
|
|
1870 |
-- forked thread) the client could try to connect to it before it's
|
|
1871 |
-- ready
|
|
1872 |
server <- run $ Luxi.getServer fpath
|
|
1873 |
-- fork the server responder
|
|
1874 |
_ <- run $ forkIO $
|
|
1875 |
bracket
|
|
1876 |
(Luxi.acceptClient server)
|
|
1877 |
(\c -> Luxi.closeClient c >> removeFile fpath)
|
|
1878 |
luxiServerPong
|
|
1879 |
replies <- run $
|
|
1880 |
bracket
|
|
1881 |
(Luxi.getClient fpath)
|
|
1882 |
Luxi.closeClient
|
|
1883 |
(\c -> luxiClientPong c msgs)
|
|
1884 |
assert $ replies == msgs
|
|
1885 |
|
1823 |
1886 |
testSuite "LUXI"
|
1824 |
1887 |
[ 'prop_Luxi_CallEncoding
|
|
1888 |
, 'prop_Luxi_ClientServer
|
1825 |
1889 |
]
|
1826 |
1890 |
|
1827 |
1891 |
-- * Ssconf tests
|