packages feed

hspec-server 0.1.0.0 → 0.2.0

raw patch · 7 files changed

+382/−220 lines, 7 filesdep +hspec-contribdep +hspec-expectationsPVP ok

version bump matches the API change (PVP)

Dependencies added: hspec-contrib, hspec-expectations

API changes (from Hackage documentation)

- Test.Hspec.Server: Debian :: String -> ServerOS
- Test.Hspec.Server: Enabled :: ServerStatus
- Test.Hspec.Server: Exit :: Int -> ServerStatus
- Test.Hspec.Server: FreeBSD :: String -> ServerOS
- Test.Hspec.Server: Installed :: ServerStatus
- Test.Hspec.Server: Listening :: ServerStatus
- Test.Hspec.Server: Localhost :: Localhost
- Test.Hspec.Server: MacOS :: String -> ServerOS
- Test.Hspec.Server: None :: ServerStatus
- Test.Hspec.Server: OtherOS :: String -> ServerOS
- Test.Hspec.Server: Running :: ServerStatus
- Test.Hspec.Server: SAnd :: (Set ServerStatus) -> ServerStatus
- Test.Hspec.Server: ServerExampleData :: !dat -> !ServerOS -> ServerExampleData dat
- Test.Hspec.Server: ServerSpecGroup :: String -> [ServerSpecTree dat] -> ServerSpecTree dat
- Test.Hspec.Server: ServerSpecItem :: String -> (ServerExample dat ()) -> ServerSpecTree dat
- Test.Hspec.Server: Ssh :: String -> Maybe String -> Maybe String -> Maybe Int -> Maybe String -> Ssh
- Test.Hspec.Server: Stderr :: String -> ServerStatus
- Test.Hspec.Server: Stdout :: String -> ServerStatus
- Test.Hspec.Server: Ubuntu :: String -> ServerOS
- Test.Hspec.Server: Vagrant :: String -> Vagrant
- Test.Hspec.Server: Windows :: String -> ServerOS
- Test.Hspec.Server: class ServerType a
- Test.Hspec.Server: cmd :: ServerType a => a -> FilePath -> [String] -> String -> IO (ExitCode, String, String)
- Test.Hspec.Server: command :: ServerType dat => FilePath -> [String] -> String -> ServerExample dat ServerStatus
- Test.Hspec.Server: data Localhost
- Test.Hspec.Server: data ServerExampleData dat
- Test.Hspec.Server: data ServerOS
- Test.Hspec.Server: data ServerSpecTree dat
- Test.Hspec.Server: data ServerStatus
- Test.Hspec.Server: data Ssh
- Test.Hspec.Server: data Vagrant
- Test.Hspec.Server: detectOS :: ServerType dat => dat -> IO (Maybe ServerOS)
- Test.Hspec.Server: getServerData :: ServerType dat => ServerExample dat dat
- Test.Hspec.Server: includes :: ServerType dat => ServerExample dat ServerStatus -> ServerStatus -> ServerExample dat ()
- Test.Hspec.Server: includes' :: ServerType dat => ServerStatus -> ServerStatus -> ServerExample dat ()
- Test.Hspec.Server: instance Eq Localhost
- Test.Hspec.Server: instance Eq ServerOS
- Test.Hspec.Server: instance Eq ServerStatus
- Test.Hspec.Server: instance Eq Ssh
- Test.Hspec.Server: instance Eq Vagrant
- Test.Hspec.Server: instance Monoid ServerStatus
- Test.Hspec.Server: instance Ord ServerStatus
- Test.Hspec.Server: instance ServerType Localhost
- Test.Hspec.Server: instance ServerType Ssh
- Test.Hspec.Server: instance ServerType Vagrant
- Test.Hspec.Server: instance Show Localhost
- Test.Hspec.Server: instance Show ServerOS
- Test.Hspec.Server: instance Show ServerStatus
- Test.Hspec.Server: instance Show Ssh
- Test.Hspec.Server: instance Show Vagrant
- Test.Hspec.Server: localhost :: Localhost
- Test.Hspec.Server: name :: ServerType a => a -> ServerName
- Test.Hspec.Server: package :: ServerType dat => String -> ServerExample dat ServerStatus
- Test.Hspec.Server: port :: ServerType dat => Int -> ServerExample dat ServerStatus
- Test.Hspec.Server: process :: ServerType dat => String -> ServerExample dat ServerStatus
- Test.Hspec.Server: sdescribe :: ServerType dat => String -> ServerSpec dat -> ServerSpec dat
- Test.Hspec.Server: serverData :: ServerExampleData dat -> !dat
- Test.Hspec.Server: serverOS :: ServerExampleData dat -> !ServerOS
- Test.Hspec.Server: serverSpec :: ServerType dat => dat -> ServerSpec dat -> Spec
- Test.Hspec.Server: serverSpecOS :: ServerType dat => dat -> ServerOS -> ServerSpec dat -> Spec
- Test.Hspec.Server: service :: ServerType dat => String -> ServerExample dat ServerStatus
- Test.Hspec.Server: sit :: ServerType dat => String -> ServerExample dat () -> ServerSpec dat
- Test.Hspec.Server: ssh :: String -> Ssh
- Test.Hspec.Server: sshConf :: Ssh -> Maybe String
- Test.Hspec.Server: sshHostName :: Ssh -> String
- Test.Hspec.Server: sshId :: Ssh -> Maybe String
- Test.Hspec.Server: sshPort :: Ssh -> Maybe Int
- Test.Hspec.Server: sshUser :: Ssh -> Maybe String
- Test.Hspec.Server: type ServerExample dat = StateT (ServerExampleData dat) IO
- Test.Hspec.Server: type ServerName = String
- Test.Hspec.Server: type ServerSpec dat = Writer [ServerSpecTree dat] ()
- Test.Hspec.Server: vHostName :: Vagrant -> String
- Test.Hspec.Server: vagrant :: String -> Vagrant
+ Test.Hspec.Server.Command: command :: ServerType dat => FilePath -> [String] -> String -> ServerExample dat CommandStatus
+ Test.Hspec.Server.Command: package :: ServerType dat => String -> ServerExample dat ServerStatus
+ Test.Hspec.Server.Command: port :: ServerType dat => Int -> ServerExample dat ServerStatus
+ Test.Hspec.Server.Command: process :: ServerType dat => String -> ServerExample dat ServerStatus
+ Test.Hspec.Server.Command: service :: ServerType dat => String -> ServerExample dat ServerStatus
+ Test.Hspec.Server.Core: describe :: ServerType dat => String -> ServerSpec dat -> ServerSpec dat
+ Test.Hspec.Server.Core: getServerData :: ServerType dat => ServerExample dat dat
+ Test.Hspec.Server.Core: getServerOS :: ServerExample dat ServerOS
+ Test.Hspec.Server.Core: includes :: (ServerType dat, Sets s) => ServerExample dat s -> s -> ServerExample dat ()
+ Test.Hspec.Server.Core: includes' :: (ServerType dat, Sets s) => s -> s -> ServerExample dat ()
+ Test.Hspec.Server.Core: it :: ServerType dat => String -> ServerExample dat () -> ServerSpec dat
+ Test.Hspec.Server.Core: serverSpec :: ServerType dat => dat -> ServerSpec dat -> Spec
+ Test.Hspec.Server.Core: serverSpecOS :: ServerType dat => dat -> ServerOS -> ServerSpec dat -> Spec
+ Test.Hspec.Server.ServerType: Localhost :: Localhost
+ Test.Hspec.Server.ServerType: Ssh :: String -> Maybe String -> Maybe String -> Maybe Int -> Maybe String -> Ssh
+ Test.Hspec.Server.ServerType: Vagrant :: String -> Maybe String -> Vagrant
+ Test.Hspec.Server.ServerType: data Localhost
+ Test.Hspec.Server.ServerType: data Ssh
+ Test.Hspec.Server.ServerType: data Vagrant
+ Test.Hspec.Server.ServerType: instance Eq Localhost
+ Test.Hspec.Server.ServerType: instance Eq Ssh
+ Test.Hspec.Server.ServerType: instance Eq Vagrant
+ Test.Hspec.Server.ServerType: instance ServerType Localhost
+ Test.Hspec.Server.ServerType: instance ServerType Ssh
+ Test.Hspec.Server.ServerType: instance ServerType Vagrant
+ Test.Hspec.Server.ServerType: instance Show Localhost
+ Test.Hspec.Server.ServerType: instance Show Ssh
+ Test.Hspec.Server.ServerType: instance Show Vagrant
+ Test.Hspec.Server.ServerType: localhost :: Localhost
+ Test.Hspec.Server.ServerType: ssh :: String -> Ssh
+ Test.Hspec.Server.ServerType: sshConf :: Ssh -> Maybe String
+ Test.Hspec.Server.ServerType: sshHostName :: Ssh -> String
+ Test.Hspec.Server.ServerType: sshId :: Ssh -> Maybe String
+ Test.Hspec.Server.ServerType: sshPort :: Ssh -> Maybe Int
+ Test.Hspec.Server.ServerType: sshUser :: Ssh -> Maybe String
+ Test.Hspec.Server.ServerType: vConf :: Vagrant -> Maybe String
+ Test.Hspec.Server.ServerType: vHostName :: Vagrant -> String
+ Test.Hspec.Server.ServerType: vagrant :: String -> Vagrant
+ Test.Hspec.Server.Type: AutoDetect :: ServerOS
+ Test.Hspec.Server.Type: CAnd :: (Set CommandStatus) -> CommandStatus
+ Test.Hspec.Server.Type: CNone :: CommandStatus
+ Test.Hspec.Server.Type: CentOS :: String -> ServerOS
+ Test.Hspec.Server.Type: Debian :: String -> ServerOS
+ Test.Hspec.Server.Type: Enabled :: ServerStatus
+ Test.Hspec.Server.Type: Exit :: Int -> CommandStatus
+ Test.Hspec.Server.Type: Fedora :: String -> ServerOS
+ Test.Hspec.Server.Type: FreeBSD :: String -> ServerOS
+ Test.Hspec.Server.Type: Installed :: ServerStatus
+ Test.Hspec.Server.Type: LinuxOther :: String -> ServerOS
+ Test.Hspec.Server.Type: Listening :: ServerStatus
+ Test.Hspec.Server.Type: MacOS :: String -> ServerOS
+ Test.Hspec.Server.Type: None :: ServerStatus
+ Test.Hspec.Server.Type: OtherOS :: String -> ServerOS
+ Test.Hspec.Server.Type: Redhat :: String -> ServerOS
+ Test.Hspec.Server.Type: Running :: ServerStatus
+ Test.Hspec.Server.Type: SAnd :: (Set ServerStatus) -> ServerStatus
+ Test.Hspec.Server.Type: ServerExampleData :: !dat -> !ServerOS -> ServerExampleData dat
+ Test.Hspec.Server.Type: ServerSpecGroup :: String -> [ServerSpecTree dat] -> ServerSpecTree dat
+ Test.Hspec.Server.Type: ServerSpecItem :: String -> (ServerExample dat ()) -> ServerSpecTree dat
+ Test.Hspec.Server.Type: Stderr :: String -> CommandStatus
+ Test.Hspec.Server.Type: Stdout :: String -> CommandStatus
+ Test.Hspec.Server.Type: Ubuntu :: String -> ServerOS
+ Test.Hspec.Server.Type: Windows :: String -> ServerOS
+ Test.Hspec.Server.Type: class ServerType a
+ Test.Hspec.Server.Type: class Show a => Sets a
+ Test.Hspec.Server.Type: cmd :: ServerType a => a -> FilePath -> [String] -> String -> IO (ExitCode, String, String)
+ Test.Hspec.Server.Type: data CommandStatus
+ Test.Hspec.Server.Type: data ServerExampleData dat
+ Test.Hspec.Server.Type: data ServerOS
+ Test.Hspec.Server.Type: data ServerSpecTree dat
+ Test.Hspec.Server.Type: data ServerStatus
+ Test.Hspec.Server.Type: detectLinux :: ServerType dat => dat -> IO (Maybe ServerOS)
+ Test.Hspec.Server.Type: detectOS :: ServerType dat => dat -> IO (Maybe ServerOS)
+ Test.Hspec.Server.Type: getStderr :: CommandStatus -> Maybe String
+ Test.Hspec.Server.Type: getStdout :: CommandStatus -> Maybe String
+ Test.Hspec.Server.Type: include :: Sets a => a -> a -> Bool
+ Test.Hspec.Server.Type: instance Eq CommandStatus
+ Test.Hspec.Server.Type: instance Eq ServerOS
+ Test.Hspec.Server.Type: instance Eq ServerStatus
+ Test.Hspec.Server.Type: instance Monoid CommandStatus
+ Test.Hspec.Server.Type: instance Monoid ServerStatus
+ Test.Hspec.Server.Type: instance Ord CommandStatus
+ Test.Hspec.Server.Type: instance Ord ServerStatus
+ Test.Hspec.Server.Type: instance ServerType dat => Example (ServerExample dat a)
+ Test.Hspec.Server.Type: instance Sets CommandStatus
+ Test.Hspec.Server.Type: instance Sets ServerStatus
+ Test.Hspec.Server.Type: instance Show CommandStatus
+ Test.Hspec.Server.Type: instance Show ServerOS
+ Test.Hspec.Server.Type: instance Show ServerStatus
+ Test.Hspec.Server.Type: name :: ServerType a => a -> ServerName
+ Test.Hspec.Server.Type: serverData :: ServerExampleData dat -> !dat
+ Test.Hspec.Server.Type: serverOS :: ServerExampleData dat -> !ServerOS
+ Test.Hspec.Server.Type: setup :: ServerType a => a -> IO a
+ Test.Hspec.Server.Type: type ServerExample dat = StateT (ServerExampleData dat) IO
+ Test.Hspec.Server.Type: type ServerName = String
+ Test.Hspec.Server.Type: type ServerSpec dat = Writer [ServerSpecTree dat] ()

Files

Test/Hspec/Server.hs view
@@ -1,215 +1,13 @@ {-# LANGUAGE OverloadedStrings #-}-module Test.Hspec.Server where--import System.Process-import System.Exit-import System.IO-import qualified Test.Hspec.Core.Spec as Hspec-import qualified Test.HUnit as HUnit-import qualified Control.Monad.Trans.State as ST-import Control.Monad.Trans.Writer-import Control.Monad.IO.Class-import System.IO.Temp--import Data.Monoid-import qualified Data.Set as S-import Text.Regex.Posix---data ServerOS =-   Ubuntu String- | Debian String- | FreeBSD String- | MacOS String- | Windows String- | OtherOS String-   deriving (Show,Eq)--type ServerName = String--class ServerType a where-  name :: a -> ServerName-  cmd :: a -> FilePath -> [String] -> String -> IO (ExitCode,String,String)--data Localhost = Localhost deriving (Show,Eq)--localhost :: Localhost-localhost = Localhost--data Ssh = Ssh {-  sshHostName :: String-, sshId :: Maybe String-, sshConf :: Maybe String-, sshPort :: Maybe Int-, sshUser :: Maybe String-} deriving (Show,Eq)--ssh :: String -> Ssh-ssh hostname = Ssh hostname Nothing Nothing Nothing Nothing--data Vagrant = Vagrant {-  vHostName :: String-} deriving (Show,Eq)--vagrant :: String -> Vagrant-vagrant hostname = Vagrant hostname--instance ServerType Localhost where-  name _ = "localhost"-  cmd _ = readProcessWithExitCode--instance ServerType Ssh where-  name = sshHostName-  cmd d c arg i = do-    readProcessWithExitCode "ssh" (sshOpt ++ [sshHost] ++ [c] ++ arg) i-    where-      sshOpt =-        (maybe [] (\v-> ["-p",show v]) (sshPort d)) ++-        (maybe [] (\v-> ["-i",show v]) (sshId d)) ++-        (maybe [] (\v-> ["-F",show v]) (sshConf d))-      sshHost = (maybe "" (\v -> v <> "@") (sshUser d)) <> sshHostName d--instance ServerType Vagrant where-  name = vHostName-  cmd d c arg i = withSystemTempFile "hspec-server" $ \file handle -> do-    (_,conf,_) <- readProcessWithExitCode "vagrant" ["ssh-config"] []-    hPutStr handle conf-    hClose handle-    readProcessWithExitCode "ssh" (["-F",file,name d,c]++arg) i--data ServerExampleData dat = ServerExampleData {-    serverData :: !dat-  , serverOS :: !ServerOS-  }--type ServerExample dat = ST.StateT (ServerExampleData dat) IO--type ServerSpec dat = Writer [ServerSpecTree dat] ()--data ServerSpecTree dat-    = ServerSpecGroup String [ServerSpecTree dat]-    | ServerSpecItem String (ServerExample dat ())--detectOS :: ServerType dat => dat -> IO (Maybe ServerOS)-detectOS _dat = return $ Just $ Ubuntu "precise"--getServerData :: ServerType dat => ServerExample dat dat-getServerData = fmap serverData ST.get--sdescribe :: ServerType dat => String -> ServerSpec dat -> ServerSpec dat-sdescribe label sspecs = tell [ServerSpecGroup label $ execWriter sspecs]--serverSpecOS :: ServerType dat-           => dat-           -> ServerOS-           -> ServerSpec dat-           -> Hspec.Spec-serverSpecOS serverData' serverOS' sspecs =-    Hspec.fromSpecList $ map unServer $ execWriter sspecs-  where-    unServer (ServerSpecGroup x y) = Hspec.specGroup x $ map unServer y-    unServer (ServerSpecItem x y) = Hspec.specItem x $ -        ST.evalStateT y ServerExampleData {-            serverData = serverData'-          , serverOS = serverOS'-         }--serverSpec :: ServerType dat-           => dat-           -> ServerSpec dat-           -> Hspec.Spec-serverSpec serverData' sspecs = do-  serverOS' <- Hspec.runIO $ detectOS serverData'-  case serverOS' of-    Just os' -> serverSpecOS serverData' os' sspecs-    Nothing -> error "can not detect os"---sit :: ServerType dat => String -> ServerExample dat () -> ServerSpec dat-sit label example = tell [ServerSpecItem label example]--data ServerStatus =-   SAnd (S.Set ServerStatus)- | Installed- | Enabled- | Running- | Listening- | Exit Int- | Stdout String- | Stderr String- | None-   deriving (Show,Ord,Eq)--instance Monoid ServerStatus where-  mempty = None-  mappend None a = a-  mappend a None = a-  mappend (SAnd a) (SAnd b) = SAnd (a<>b)-  mappend (SAnd a) b = SAnd (a <> S.singleton b)-  mappend a (SAnd b) = SAnd (S.singleton a <> b)-  mappend a b = SAnd (S.singleton a <> S.singleton b)---includes' :: ServerType dat => ServerStatus -> ServerStatus -> ServerExample dat ()-includes' org ex =-  liftIO $ flip HUnit.assertBool (includes'' org ex) $ concat-    [ "Expected status was ", show ex-    , " but received status was ", show org-    ]-  where-    includes'' :: ServerStatus -> ServerStatus -> Bool-    includes'' (SAnd org') (SAnd exp') = flip S.isSubsetOf org' exp'-    includes'' org' (SAnd exp') = flip S.isSubsetOf (S.singleton org') exp'-    includes'' (SAnd org') exp' = flip S.isSubsetOf org' (S.singleton exp')-    includes'' org' exp' = flip S.isSubsetOf (S.singleton org') (S.singleton exp')--includes :: ServerType dat => ServerExample dat ServerStatus -> ServerStatus -> ServerExample dat ()-includes org' ex = do-  org <- org'-  org `includes'` ex--package :: ServerType dat => String -> ServerExample dat ServerStatus-package pkg = do-  dat <- getServerData-  (_,out,_) <- liftIO $ cmd dat "dpkg" ["-l",pkg] []-  if or (map (\v -> v  =~ ("^ii +" <> pkg <> " ")) (lines out))-    then return Installed-    else return None--process :: ServerType dat => String -> ServerExample dat ServerStatus-process ps = do-  dat <- getServerData-  (code,_,_) <- liftIO $ cmd dat "pgrep" [ps] []-  if code == ExitSuccess-    then return Running-    else return None--service :: ServerType dat => String -> ServerExample dat ServerStatus-service s = do-  dat <- getServerData-  (_,out,_) <- liftIO $ cmd dat ("/etc/init.d/"++s) ["status"] []-  if or (map (\v ->-               (v  =~ ("is running" :: String)) ||-               (v  =~ ("start/running" :: String))-             ) (lines out))-    then return Running-    else return None--port :: ServerType dat => Int -> ServerExample dat ServerStatus-port p = do-  dat <- getServerData-  (_,out,_) <- liftIO $ cmd dat "netstat" ["-tanp"] []-  if or (map (\v ->-               (v  =~ ("^tcp[ 6] +[0-9]+ +[0-9]+ :::" <> show p <> " +[^ ]+ +LISTEN")) ||-               (v  =~ ("^tcp[ 6] +[0-9]+ +[0-9]+ [0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+:" <> show p <> " +[^ ]+ +LISTEN"))-             ) (lines out))-    then return Listening-    else return None+module Test.Hspec.Server (+  module Test.Hspec.Server.Type+, module Test.Hspec.Server.Core+, module Test.Hspec.Server.ServerType+, module Test.Hspec.Server.Command+  )+where -command :: ServerType dat => FilePath -> [String] -> String -> ServerExample dat ServerStatus-command c arg inp = do-  dat <- getServerData-  (code,out,err) <- liftIO $ cmd dat c arg inp-  let genCode ExitSuccess =  0-      genCode (ExitFailure val) =  val-  return $ Exit (genCode code) <> Stdout out <> Stderr err+import Test.Hspec.Server.Type+import Test.Hspec.Server.Core+import Test.Hspec.Server.ServerType+import Test.Hspec.Server.Command
+ Test/Hspec/Server/Command.hs view
@@ -0,0 +1,54 @@+module Test.Hspec.Server.Command where++import System.Exit+import Control.Monad.IO.Class+import Data.Monoid+import Text.Regex.Posix+import Test.Hspec.Server.Type+import Test.Hspec.Server.Core++package :: ServerType dat => String -> ServerExample dat ServerStatus+package pkg = do+  dat <- getServerData+  (_,out,_) <- liftIO $ cmd dat "dpkg" ["-l",pkg] []+  if or (map (\v -> v  =~ ("^ii +" <> pkg <> " ")) (lines out))+    then return Installed+    else return None++process :: ServerType dat => String -> ServerExample dat ServerStatus+process ps = do+  dat <- getServerData+  (code,_,_) <- liftIO $ cmd dat "pgrep" [ps] []+  if code == ExitSuccess+    then return Running+    else return None++service :: ServerType dat => String -> ServerExample dat ServerStatus+service s = do+  dat <- getServerData+  (_,out,_) <- liftIO $ cmd dat ("/etc/init.d/"++s) ["status"] []+  if or (map (\v ->+               (v  =~ ("is running" :: String)) ||+               (v  =~ ("start/running" :: String))+             ) (lines out))+    then return Running+    else return None++port :: ServerType dat => Int -> ServerExample dat ServerStatus+port p = do+  dat <- getServerData+  (_,out,_) <- liftIO $ cmd dat "netstat" ["-tanp"] []+  if or (map (\v ->+               (v  =~ ("^tcp[ 6] +[0-9]+ +[0-9]+ :::" <> show p <> " +[^ ]+ +LISTEN")) ||+               (v  =~ ("^tcp[ 6] +[0-9]+ +[0-9]+ [0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+:" <> show p <> " +[^ ]+ +LISTEN"))+             ) (lines out))+    then return Listening+    else return None++command :: ServerType dat => FilePath -> [String] -> String -> ServerExample dat CommandStatus+command c arg inp = do+  dat <- getServerData+  (code,out,err) <- liftIO $ cmd dat c arg inp+  let genCode ExitSuccess =  0+      genCode (ExitFailure val) =  val+  return $ Exit (genCode code) <> Stdout out <> Stderr err
+ Test/Hspec/Server/Core.hs view
@@ -0,0 +1,64 @@++module Test.Hspec.Server.Core where++import qualified Test.Hspec.Core.Spec as Hspec+import qualified Test.HUnit as HUnit+import Control.Monad.Trans.Writer+import Control.Monad.IO.Class+import qualified Control.Monad.Trans.State as ST+import Test.Hspec.Server.Type++serverSpecOS :: ServerType dat+           => dat+           -> ServerOS+           -> ServerSpec dat+           -> Hspec.Spec+serverSpecOS serverData' serverOS' sspecs = do+    dat' <- Hspec.runIO $ setup serverData'+    os' <- case serverOS' of+             AutoDetect -> do+               v <- Hspec.runIO $ detectOS dat'+               case v of+                 Just v' -> return v'+                 Nothing -> error "can not detect os"+             _ -> return serverOS'+    Hspec.fromSpecList $ map (unServer (dat',os')) $ execWriter sspecs+  where+    unServer (dat',os') (ServerSpecGroup x y) = Hspec.specGroup x $ map (unServer (dat',os')) y+    unServer (dat',os') (ServerSpecItem x y) = Hspec.specItem x $ +        ST.evalStateT y ServerExampleData {+            serverData = dat'+          , serverOS = os'+         }++serverSpec :: ServerType dat+           => dat+           -> ServerSpec dat+           -> Hspec.Spec+serverSpec serverData' sspecs = do+  serverSpecOS serverData' AutoDetect sspecs++getServerData :: ServerType dat => ServerExample dat dat+getServerData = fmap serverData ST.get++getServerOS :: ServerExample dat ServerOS+getServerOS = fmap serverOS ST.get++it :: ServerType dat => String -> ServerExample dat () -> ServerSpec dat+it label example = tell [ServerSpecItem label example]++describe :: ServerType dat => String -> ServerSpec dat -> ServerSpec dat+describe label sspecs = tell [ServerSpecGroup label $ execWriter sspecs]++includes' :: (ServerType dat, Sets s) => s -> s -> ServerExample dat ()+includes' org ex =+  liftIO $ flip HUnit.assertBool (include org ex) $ concat+    [ "Expected status was ", show ex+    , " but received status was ", show org+    ]++includes :: (ServerType dat, Sets s) => ServerExample dat s -> s -> ServerExample dat ()+includes org' ex = do+  org <- org'+  org `includes'` ex+
+ Test/Hspec/Server/ServerType.hs view
@@ -0,0 +1,64 @@+module Test.Hspec.Server.ServerType where++import System.Process+import System.Exit+import System.IO.Temp+import System.IO+import Data.Monoid+import Data.Maybe+import Control.Monad+import Test.Hspec.Server.Type++data Localhost = Localhost deriving (Show,Eq)++localhost :: Localhost+localhost = Localhost++instance ServerType Localhost where+  setup a = return a+  name _ = "localhost"+  cmd _ = readProcessWithExitCode++data Ssh = Ssh {+  sshHostName :: String+, sshId :: Maybe String+, sshConf :: Maybe String+, sshPort :: Maybe Int+, sshUser :: Maybe String+} deriving (Show,Eq)++ssh :: String -> Ssh+ssh hostname = Ssh hostname Nothing Nothing Nothing Nothing++instance ServerType Ssh where+  setup a = return a+  name = sshHostName+  cmd d c arg i = do+    readProcessWithExitCode "ssh" (sshOpt ++ [sshHost] ++ [c] ++ arg) i+    where+      sshOpt =+        (maybe [] (\v-> ["-p",show v]) (sshPort d)) +++        (maybe [] (\v-> ["-i",show v]) (sshId d)) +++        (maybe [] (\v-> ["-F",show v]) (sshConf d))+      sshHost = (maybe "" (\v -> v <> "@") (sshUser d)) <> sshHostName d++data Vagrant = Vagrant {+   vHostName :: String+ , vConf :: Maybe String+} deriving (Show,Eq)++vagrant :: String -> Vagrant+vagrant hostname = Vagrant hostname Nothing++instance ServerType Vagrant where+  setup a = do+    (e,conf,_) <- readProcessWithExitCode "vagrant" ["ssh-config"] []+    when (e /= ExitSuccess) $ do+      error "vagrant setup error"+    return $ a {vConf = Just conf}+  name = vHostName+  cmd d c arg i = withSystemTempFile "hspec-server" $ \file handle -> do+    hPutStr handle (fromJust (vConf d))+    hClose handle+    readProcessWithExitCode "ssh" (["-F",file,name d,c]++arg) i+
+ Test/Hspec/Server/Type.hs view
@@ -0,0 +1,162 @@+{-# LANGUAGE CPP, TypeFamilies, FlexibleInstances, TypeSynonymInstances, DeriveDataTypeable #-}+module Test.Hspec.Server.Type where++import System.Exit+import qualified Control.Monad.Trans.State as ST+import Control.Monad.Trans.Writer+import qualified Test.Hspec.Core.Spec as Hspec++import Data.Monoid+import Data.List+import Data.Maybe+import qualified Data.Set as S++data ServerOS =+   Ubuntu String+ | Debian String+ | CentOS String+ | Fedora String+ | Redhat String+ | LinuxOther String+ | FreeBSD String+ | MacOS String+ | Windows String+ | OtherOS String+ | AutoDetect+   deriving (Show,Eq)++type ServerName = String++class ServerType a where+  setup :: a -> IO a+  name :: a -> ServerName+  cmd :: a -> FilePath -> [String] -> String -> IO (ExitCode,String,String)++data ServerExampleData dat = ServerExampleData {+    serverData :: !dat+  , serverOS :: !ServerOS+  }++type ServerExample dat = ST.StateT (ServerExampleData dat) IO++instance (ServerType dat) => Hspec.Example (ServerExample dat a) where+  type Arg (ServerExample dat a) = dat+  evaluateExample example params action =+    Hspec.evaluateExample+      (action $ \dat' -> do+        os <- detectOS dat'+        _ <- ST.evalStateT example ServerExampleData {+            serverData = dat'+          , serverOS = fromJust os+          }+        return ())+      params+      ($ ())++type ServerSpec dat = Writer [ServerSpecTree dat] ()++data ServerSpecTree dat+    = ServerSpecGroup String [ServerSpecTree dat]+    | ServerSpecItem String (ServerExample dat ())++class Show a => Sets a where+  include :: a -> a -> Bool++data ServerStatus =+   SAnd (S.Set ServerStatus)+ | Installed+ | Enabled+ | Running+ | Listening+ | None+   deriving (Show,Ord,Eq)++instance Monoid ServerStatus where+  mempty = None+  mappend None a = a+  mappend a None = a+  mappend (SAnd a) (SAnd b) = SAnd (a<>b)+  mappend (SAnd a) b = SAnd (a <> S.singleton b)+  mappend a (SAnd b) = SAnd (S.singleton a <> b)+  mappend a b = SAnd (S.singleton a <> S.singleton b)++data CommandStatus =+   CAnd (S.Set CommandStatus)+ | Exit Int+ | Stdout String+ | Stderr String+ | CNone+   deriving (Show,Ord,Eq)++instance Monoid CommandStatus where+  mempty = CNone+  mappend CNone a = a+  mappend a CNone = a+  mappend (CAnd a) (CAnd b) = CAnd (a<>b)+  mappend (CAnd a) b = CAnd (a <> S.singleton b)+  mappend a (CAnd b) = CAnd (S.singleton a <> b)+  mappend a b = CAnd (S.singleton a <> S.singleton b)++instance Sets ServerStatus where+  include (SAnd org') (SAnd exp') = flip S.isSubsetOf org' exp'+  include org' (SAnd exp') = flip S.isSubsetOf (S.singleton org') exp'+  include (SAnd org') exp' = flip S.isSubsetOf org' (S.singleton exp')+  include org' exp' = flip S.isSubsetOf (S.singleton org') (S.singleton exp')++instance Sets CommandStatus where+  include (CAnd org') (CAnd exp') = flip S.isSubsetOf org' exp'+  include org' (CAnd exp') = flip S.isSubsetOf (S.singleton org') exp'+  include (CAnd org') exp' = flip S.isSubsetOf org' (S.singleton exp')+  include org' exp' = flip S.isSubsetOf (S.singleton org') (S.singleton exp')++getStdout :: CommandStatus -> Maybe String+getStdout (Stdout code) = Just code+getStdout (CAnd statuss) = listToMaybe $ catMaybes $ map getStdout $ S.toList statuss+getStdout _ = Nothing++getStderr :: CommandStatus -> Maybe String+getStderr (Stderr code) = Just code+getStderr (CAnd statuss) = listToMaybe $ catMaybes $ map getStdout $ S.toList statuss+getStderr _ = Nothing+++detectOS :: ServerType dat => dat -> IO (Maybe ServerOS)+detectOS dat = do+  (_,out,_) <- cmd dat "sh" ["-c","echo $OSTYPE"] []+  case (head (lines out)) of+    "linux-gnu" -> detectLinux dat+    'd':'a':'r':'w':'i':'n':o -> return $ Just $ MacOS o+    "msys" -> return $ Just $ Windows "msys"+    "cygwin" -> return $ Just $ Windows "cygwin"+    "win32" -> return $ Just $ Windows "win32"+    "win64" -> return $ Just $ Windows "win64"+    'f':'r':'e':'e':'b':'s':'d':o -> return $ Just $ FreeBSD o+    o -> return $ Just $ OtherOS o++detectLinux :: ServerType dat => dat -> IO (Maybe ServerOS)+detectLinux dat = do+  (_code,_out,_) <- cmd dat "cat" ["/etc/lsb-release"] []+  if _code == ExitSuccess+    then do+      let tag = "DISTRIB_RELEASE="+      let v = listToMaybe $ map (drop (length tag)) $ filter (isPrefixOf "DISTRIB_RELEASE=") (lines _out)+      case v of+        Just v' -> return $ Just $ Ubuntu v'+        Nothing -> return $ Just $ Ubuntu ""+    else do+      (_code,_out,_) <- cmd dat "cat" ["/etc/debian_version"] []+      if _code == ExitSuccess+        then return $ Just $ Debian _out+        else do+          (_code,_out,_) <- cmd dat "cat" ["/etc/centos-release"] []+          if _code == ExitSuccess+            then return $ Just $ CentOS _out+            else do+              (_code,_out,_) <- cmd dat "cat" ["/etc/fedora-release"] []+              if _code == ExitSuccess+                then return $ Just $ Fedora _out+                else do+                  (_code,_out,_) <- cmd dat "cat" ["/etc/redhat-release"] []+                  if _code == ExitSuccess+                    then return $ Just $ Fedora _out+                    else return $ Just $ LinuxOther ""
hspec-server.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                hspec-server-version:             0.1.0.0+version:             0.2.0 synopsis:            Test Framework for Server's status description:         Hspec-Server is test framework for checking server's status.                      It is inspired by the Ruby library ServerSpec.@@ -16,13 +16,22 @@ -- extra-source-files:   cabal-version:       >=1.10 +source-repository head+        type:           git+        location:       https://github.com/junjihashimoto/hspec-server.git+ library   exposed-modules:     Test.Hspec.Server+                     , Test.Hspec.Server.Type+                     , Test.Hspec.Server.Core+                     , Test.Hspec.Server.ServerType+                     , Test.Hspec.Server.Command   -- other-modules:          -- other-extensions:       build-depends:       base >=4.6 && <5                      , hspec >= 2                      , hspec-core >= 2+                     , hspec-expectations                      , transformers                      , process                      , temporary@@ -40,5 +49,7 @@      build-depends: base                  , hspec+                 , hspec-contrib                  , hspec-server+                 , transformers     Default-Language:   Haskell2010
test/test.hs view
@@ -1,16 +1,25 @@-import Test.Hspec+import Test.Hspec hiding (it,describe) import Test.Hspec.Server+import Test.Hspec.Contrib.Retry+import Control.Monad.IO.Class  main :: IO () main = hspec $ do   serverSpec localhost $ do-    sdescribe "hoge" $ do-      sit "package test" $ do+    describe "hoge" $ do+      it "package test" $ do+        dat <- getServerData+        os <- liftIO $ detectOS dat+        liftIO $ os `shouldBe` (Just $ Ubuntu "14.04")+      it "package test" $ do         package "zookeeper" `includes` Installed-      sit "port test" $ do+      it "port test" $ do         port 2181 `includes` Listening-      sit "service test" $ do+      it "service test" $ do         service "cron" `includes` Running         service "atd" `includes` Running-      sit "command test" $ do+      it "command test" $ do         command "ls" [] [] `includes` Exit 0+      it "retry test" $ do+        retryWith 10 $ --currently does not support Retry. I want to use retryWith !!!+          command "ls" [] [] `includes` Exit 0