{-# 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" (mapM_ yield . L.toChunks $ L.fromStrict 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