packages feed

test-sandbox-0.1.4: test/test.hs

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE CPP #-}
import Test.Hspec hiding (shouldReturn,shouldBe)
import Test.Hspec.Expectations.Lifted
import Test.QuickCheck
import Test.QuickCheck.Monadic (assert,monadicIO)
import Test.Sandbox
import qualified Test.Sandbox.Internals as I
import Text.Heredoc
import qualified Text.Hastache as H
import qualified Text.Hastache.Context as H
import qualified Data.Text.Lazy as TL
import qualified Data.Text as T
import qualified Data.Map as M
import System.Posix.Files
import System.Exit (ExitCode(..))
import Data.IORef
import Data.Char
import Control.Concurrent

a2b :: String -> String
a2b [] = []
a2b ('a':xs) = 'b':xs
a2b (x:xs) = x:a2b xs

a2btest :: I.SandboxStateRef -> [Char] -> Property
a2btest ref str' = a2btest' ref $ filter isAlphaNum str'

a2btest' :: I.SandboxStateRef -> [Char] -> Property
a2btest' ref str' =
  monadicIO $ do
    v <- liftIO $ runSandbox' ref $ interactWith "sed_regex" (str' ++ "\n") 1
    assert $ v == ((a2b str') ++ "\n")

main :: IO ()
main = withSandbox $ \gref -> do
  hspec $ do
    describe "Basic Test" $ do
      it "Run server like nc : port 12181" $ do
        runSandbox' gref $ do
          file <- setFile "ncfile1"
                  [str|import Network
                      |import System.IO
                      |import Control.Monad
                      |import Control.Concurrent
                      |
                      |main :: IO ()
                      |main = withSocketsDo $ do
                      |  let val = "hoge\n"
                      |  sock <- listenOn $ PortNumber 12181
                      |  forever $ do
                      |    (handle, _host, _port) <- accept sock
                      |    forkFinally (talk handle val) (\_ -> hClose handle)
                      |  where
                      |    talk h val = do
                      |      hPutStr h val
                      |      v <-  hGetContents h
                      |      putStr v
                      |]
          --liftIO $ setExecuteMode file
          start =<< register "ncserver1" "runhaskell" [file] def { psCapture = Just CaptureStdout }
      it "isBinable' 12181" $ do
        I.isBindable' 12181 `shouldReturn` False
      it "isBinable' 12180" $ do
        I.isBindable' 12180 `shouldReturn` True
      it "Test isBinable 12181" $ do
        I.isBindable 12181 `shouldReturn` False
      it "Test isBinable 12180" $ do
        I.isBindable 12180 `shouldReturn` True
      it "Test sendTo" $ do
        runSandbox' gref $ do
          p <- getPort "ncport"
          file <- setFile' "ncfile"
                  [("port",p)]
                  [str|import Network
                      |import System.IO
                      |import Control.Monad
                      |import Control.Concurrent
                      |
                      |main :: IO ()
                      |main = withSocketsDo $ do
                      |  let val = "hoge\n"
                      |  sock <- listenOn $ PortNumber {{port}}
                      |  forever $ do
                      |    (handle, _host, _port) <- accept sock
                      |    forkFinally (talk handle val) (\_ -> hClose handle)
                      |  where
                      |    talk h val = do
                      |      hPutStr h val
                      |      v <-  hGetContents h
                      |      putStr v
                      |]
          liftIO $ I.isBindable p `shouldReturn` True
          -- liftIO $ setExecuteMode file
          start =<< register "ncserver" "runhaskell" [file] def { psCapture = Just CaptureStdout }
          liftIO $ I.isBindable p `shouldReturn` False
          sendTo "ncport" "hogehoge\n" 1 `shouldReturn` "hoge\n"
      it "interactive Test by sandbox" $ do
        sandbox "hogehoge" $ do
          start =<< register "sed_regex" "sed" [ "-u", "s/a/b/" ] def { psCapture = Just CaptureStdout }
          v <- interactWith "sed_regex" "a\n" 1
          liftIO $ v `shouldBe` "b\n"
      it "interactive Test by withSandbox" $ do
        withSandbox $ \ref -> do
          val <- runSandbox' ref $ do
            start =<< register "sed_regex" "sed" [ "-u", "s/a/b/" ] def { psCapture = Just CaptureStdout }
            interactWith "sed_regex" "a\n" 1
          val `shouldBe` "b\n"
      it "interactive Test : QuickCheck(setup)" $ do
        val <- runSandbox' gref $ do
          start =<< register "sed_regex" "sed" [ "-u", "s/a/b/" ] def { psCapture = Just CaptureStdout }
          interactWith "sed_regex" "a\n" 1
        val `shouldBe` "b\n"
      it "interactive Test : QuickCheck(run)" $
        property $ a2btest gref
      it "setFile" $ do
        withSandbox $ \ref -> do
          let content =
                  [str|#!/bin/env bash
                      |while true ; do echo hhh ; sleep 1;done
                      |]
          putStr content
          file <- runSandbox' ref $ setFile "str1" content
          readFile file `shouldReturn`  content
      it "set/getVariable" $ do
        withSandbox $ \ref -> do
          runSandbox' ref $ do
            v <- I.isVerbose
            liftIO $ v `shouldBe` True
            _ <- setVariable I.verbosityKey False
            v' <- I.isVerbose
            liftIO $ v' `shouldBe` False
          runSandbox' ref I.isVerbose `shouldReturn` False
          _ <- runSandbox' ref $ setVariable I.verbosityKey True
          runSandbox' ref I.isVerbose `shouldReturn` True
      it ": run" $ do
        withSandbox $ \ref -> runSandbox' ref $ do
          file <- setFile "echoecho"
                  [str|#!/usr/bin/env bash
                      |echo "echoecho"
                      |]
          liftIO $ setExecuteMode file

          pname1 <- register "echo1" file [] def
          (exitCode1, mStr1) <- run pname1 1
          liftIO $ exitCode1 `shouldBe` ExitSuccess
          liftIO $ mStr1 `shouldBe` Nothing

          pname2 <- register "echo2" file [] def { psCapture = Just CaptureStdout }
          (exitCode2, mStr2) <- run pname2 1
          liftIO $ exitCode2 `shouldBe` ExitSuccess
          liftIO $ mStr2 `shouldBe` Just "echoecho\n"

#if defined(__MACOSX__) ||  defined(__WIN32__)
#else
    describe "signal test" $ do
      it "send kill signal for process groups" $ do
        val <- newIORef $ error "do not eval this"
        withSandbox $ \ref -> runSandbox' ref $ do
          file <- setFile "str1"
                  [str|#!/usr/bin/env bash
                      |trap "echo catch signal" 1 2 3 15
                      |while true ; do echo hhh ; sleep 1;done
                      |]
          liftIO $ setExecuteMode file
          fil2 <- setFile' "str2"
                  [("file",file)]
                  [str|#!/usr/bin/env bash
                      |trap "echo catch signal" 1 2 3 15
                      |{{file}}&
                      |{{file}}&
                      |{{file}}&
                      |while true ; do echo hhh ; sleep 1;done
                      |]
          liftIO $ setExecuteMode fil2
          _ <- register "scr1" fil2 [] def
          startAll
          liftIO $ writeIORef val ref
          pids <- I.getAvailablePids
          liftIO $ threadDelay $ 1 * 1000 * 1000
          liftIO $ (length pids >= 4) `shouldBe` True
        ref' <- readIORef val
        pids <- runSandbox' ref' $ I.getAvailablePids
        length pids `shouldBe` 0

      it "send kill signal for process groups" $ do
        sandbox "test" $ do
          file <- setFile "str1"
                  [str|#!/usr/bin/env bash
                      |trap "echo catch signal" 1 2 3 15
                      |while true ; do echo hhh ; sleep 1;done
                      |]
          liftIO $ setExecuteMode file
          fil2 <- setFile' "str2"
                  [("file",file)]
                  [str|#!/usr/bin/env bash
                      |trap "echo catch signal" 1 2 3 15
                      |{{file}}&
                      |{{file}}&
                      |{{file}}&
                      |while true ; do echo hhh ; sleep 1;done
                      |]
          liftIO $ setExecuteMode fil2
          _ <- register "scr1" fil2 [] def
          startAll
          pids <- I.getAvailablePids
          liftIO $ (length pids >= 4) `shouldBe` True
      it "not send kill signal for process groups" $ do
        val <- newIORef $ error "do not eval this"
        withSandbox $ \ref -> runSandbox' ref $ do
          file <- setFile "str1"
                  [str|#!/usr/bin/env bash
                      |trap "echo catch signal" 1 2 3 15
                      |while true ; do echo hhh ; sleep 1;done
                      |]
          liftIO $ setExecuteMode file
          fil2 <- setFile' "str2"
                  [("file",file)]
                  [str|#!/usr/bin/env bash
                      |trap "echo catch signal" 1 2 3 15
                      |{{file}}&
                      |{{file}}&
                      |{{file}}&
                      |while true ; do echo hhh ; sleep 1;done
                      |]
          liftIO $ setExecuteMode fil2
          _ <- register "scr1" fil2 [] def
          startAll
          _ <- setVariable I.cleanUpKey False
          pids <- I.getAvailablePids
          liftIO $ writeIORef val ref
          liftIO $ do
            (length pids >= 4) `shouldBe` True
        ref' <- readIORef val
        pids <- runSandbox' ref' $ I.getAvailablePids
        (length pids > 0 ) `shouldBe` True
        pids' <- runSandbox' ref' $ do
          I.cleanUpProcesses
          I.getAvailablePids
        length pids' `shouldBe` 0
#endif

setFile' :: H.MuVar a
         => String
         -> [(String, a)]
         -> String
         -> Sandbox FilePath
setFile' filename keyValues template  = do
  str' <- H.hastacheStr
          H.defaultConfig
          (H.encodeStr template)
          (H.mkStrContext context')
  setFile filename $ T.unpack $ TL.toStrict str'
  where
    context' str' = (M.fromList (map (\(k,v) -> (k,H.MuVariable v)) keyValues)) M.! str'

setExecuteMode :: FilePath -> IO ()
setExecuteMode file = do
  stat <- getFileStatus file
  setFileMode file (fileMode stat `unionFileModes` ownerExecuteMode)