{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
module Data.Conduit.ProcessSpec (spec, main) where
import Test.Hspec
import Test.Hspec.QuickCheck (prop)
import Data.Conduit
import qualified Data.Conduit.List as CL
import Data.Conduit.Process
import Control.Concurrent.Async (concurrently)
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString as S
import qualified Data.ByteString.Char8 as S8
import System.Exit
import Control.Concurrent (threadDelay)
main :: IO ()
main = hspec spec
spec :: Spec
spec = describe "Data.Conduit.Process" $ do
#ifndef WINDOWS
prop "cat" $ \wss -> do
let lbs = L.fromChunks $ map S.pack wss
((sink, closeStdin), source, Inherited, cph) <- streamingProcess (shell "cat")
((), bss) <- concurrently
(do
mapM_ yield (L.toChunks lbs) $$ sink
closeStdin)
(source $$ CL.consume)
L.fromChunks bss `shouldBe` lbs
ec <- waitForStreamingProcess cph
ec `shouldBe` ExitSuccess
it "closed stream" $ do
(ClosedStream, source, Inherited, cph) <- streamingProcess (shell "cat")
bss <- source $$ CL.consume
bss `shouldBe` []
ec <- waitForStreamingProcess cph
ec `shouldBe` ExitSuccess
it "handles sub-process exit code" $ do
(sourceCmdWithConsumer "exit 0" CL.sinkNull)
`shouldReturn` (ExitSuccess, ())
(sourceCmdWithConsumer "exit 11" CL.sinkNull)
`shouldReturn` (ExitFailure 11, ())
(sourceCmdWithConsumer "exit 12" CL.sinkNull)
`shouldReturn` (ExitFailure 12, ())
(sourceCmdWithStreams "exit 0" CL.sourceNull CL.sinkNull CL.sinkNull)
`shouldReturn` (ExitSuccess, (), ())
(sourceCmdWithStreams "exit 11" CL.sourceNull CL.sinkNull CL.sinkNull)
`shouldReturn` (ExitFailure 11, (), ())
(sourceCmdWithStreams "exit 12" CL.sourceNull CL.sinkNull CL.sinkNull)
`shouldReturn` (ExitFailure 12, (), ())
it "consumes stdout" $ do
let mystr = "this is a test string" :: String
sourceCmdWithStreams ("bash -c \"echo -n " ++ mystr ++ "\"")
CL.sourceNull
CL.consume -- stdout
CL.consume -- stderr
`shouldReturn` (ExitSuccess, [S8.pack mystr], [])
it "consumes stderr" $ do
let mystr = "this is a test string" :: String
sourceCmdWithStreams ("bash -c \">&2 echo -n " ++ mystr ++ "\"")
CL.sourceNull
CL.consume -- stdout
CL.consume -- stderr
`shouldReturn` (ExitSuccess, [], [S8.pack mystr])
it "feeds stdin" $ do
let mystr = "this is a test string" :: S.ByteString
sourceCmdWithStreams "cat"
(yield mystr)
CL.consume -- stdout
CL.consume -- stderr
`shouldReturn` (ExitSuccess, [mystr], [])
#endif
it "blocking vs non-blocking" $ do
(ClosedStream, ClosedStream, ClosedStream, cph) <- streamingProcess (shell "sleep 1")
mec1 <- getStreamingProcessExitCode cph
mec1 `shouldBe` Nothing
threadDelay 1500000
-- For slow systems where sleep may take longer than 1.5 seconds, do
-- this in a loop.
let loop 0 = error "Took too long for sleep to exit, your system is acting funny"
loop i = do
mec2 <- getStreamingProcessExitCode cph
case mec2 of
Nothing -> do
threadDelay 500000
loop (pred i)
Just _ -> mec2 `shouldBe` Just ExitSuccess
loop (5 :: Int)
ec <- waitForStreamingProcess cph
ec `shouldBe` ExitSuccess