packages feed

test-sandbox-0.1.9: test/test.hs

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
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.Mustache 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
import Data.String.Conversions

import Network.Socket
import Network.Socket.ByteString (sendAll,recv)
import Network.Run.TCP
import System.IO
import Control.Monad
import Data.Aeson
import Data.Aeson.Types (Pair)


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")

mainEcho :: IO ()
mainEcho = do
  let val = "hoge\n"
  runTCPServer Nothing "12181" (talk val)
  where
    talk val s = do
      sendAll s val
      msg <- recv s 1024
      sendAll s msg

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|{-# LANGUAGE OverloadedStrings #-}
                      |import qualified Data.ByteString as B
                      |import Network.Socket.ByteString
                      |import Network.Socket
                      |import Network.Run.TCP
                      |main = do
                      |  let val = "hoge\n"
                      |  runTCPServer Nothing "12181" (talk val)
                      |  where
                      |    talk val s = do
                      |      sendAll s val
                      |      msg <- recv s 1024
                      |      B.putStr msg
                      |]
          --liftIO $ setExecuteMode file
          start =<< register "ncserver1" "runghc" [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",toJSON p)]
                  [str|{-# LANGUAGE OverloadedStrings #-}
                      |import qualified Data.ByteString as B
                      |import Network.Socket.ByteString
                      |import Network.Socket
                      |import Network.Run.TCP
                      |main = do
                      |  let val = "hoge\n"
                      |  runTCPServer Nothing "{{port}}" (talk val)
                      |  where
                      |    talk val s = do
                      |      sendAll s val
                      |      msg <- recv s 1024
                      |      B.putStr msg
                      |]
          liftIO $ I.isBindable p `shouldReturn` True
          -- liftIO $ setExecuteMode file
          start =<< register "ncserver" "runghc" [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"
--     ToDo: This test fails in local linux. 
--      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",toJSON 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
        let chkpid  :: IO Int
            chkpid = do
              threadDelay (5 * 1000 * 1000)
              pids <- runSandbox' ref' $ I.getAvailablePids
              return $ length pids
        chkpid `shouldReturn` 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",toJSON 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",toJSON 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' :: String
         -> [Pair]
         -> String
         -> Sandbox FilePath
setFile' filename keyValues template  = do
  str' <- case (H.compileMustacheText (H.PName (cs filename)) (cs template)) of 
    Left err -> fail $ show err
    Right template -> do
      return $ H.renderMustache template (object keyValues)
  setFile filename $ cs str'

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