beam-postgres-0.4.0.0: test/Database/Beam/Postgres/Test.hs
{-# LANGUAGE CPP #-}
module Database.Beam.Postgres.Test where
#if MIN_VERSION_base(4,12,0)
import Prelude hiding (fail)
#endif
import qualified Database.PostgreSQL.Simple as Pg
import Control.Exception (SomeException(..), bracket, catch)
import Control.Concurrent (threadDelay)
import Control.Monad (void)
#if MIN_VERSION_base(4,12,0)
import Control.Monad.Fail (MonadFail(..))
#endif
import Data.ByteString (ByteString)
import Data.Semigroup
import Data.String
import qualified Hedgehog
import System.IO.Temp
import System.Process
import System.Exit
import System.FilePath
import System.Directory
withTestPostgres :: String -> IO ByteString -> (Pg.Connection -> IO a) -> IO a
withTestPostgres dbName getConnStr action = do
connStr <- getConnStr
let connStrTemplate1 = connStr <> " dbname=template1"
connStrDb = connStr <> " dbname=" <> fromString dbName
withTemplate1 :: (Pg.Connection -> IO b) -> IO b
withTemplate1 = bracket (Pg.connectPostgreSQL connStrTemplate1) Pg.close
createDatabase = withTemplate1 $ \c -> do
Pg.execute_ c (fromString ("CREATE DATABASE " <> dbName))
Pg.connectPostgreSQL connStrDb
dropDatabase c = do
Pg.close c
withTemplate1 $ \c' -> do
Pg.execute_ c' (fromString ("DROP DATABASE " <> dbName))
pure ()
bracket createDatabase dropDatabase action
startTempPostgres :: IO (ByteString, IO ())
startTempPostgres = do
tmpDir <- getCanonicalTemporaryDirectory
pgDataDir <- createTempDirectory tmpDir "postgres-data"
callProcess "pg_ctl" [ "init", "-D", pgDataDir ]
-- Use 'D' because otherwise, the path is too long on OS X
pgHdl <- spawnProcess "postgres"
[ "-D", pgDataDir
, "-k", pgDataDir, "-h", "" ]
putStrLn ("Using " ++ pgDataDir ++ " as postgres host")
let waitForPort 10 = fail "Could not connect to postgres"
waitForPort n = do
(code, stdout, stderr) <- readProcessWithExitCode "pg_ctl" [ "status", "-D", pgDataDir ] ""
case code of
ExitSuccess -> waitForSocket 0
ExitFailure _ -> threadDelay 1000000 >> waitForPort (n + 1)
waitForSocket 10 = fail "Could not connect to postgres (waitForSocket)"
waitForSocket n = do
skExists <- doesFileExist (pgDataDir </> ".s.PGSQL.5432")
if skExists then pure () else threadDelay 1000000 >> waitForSocket (n + 1)
waitForPort 0
putStrLn "Completed waiting for postgres"
pure ( fromString ("host=" ++ pgDataDir)
, void (callProcess "pg_ctl" [ "stop", "-D", pgDataDir ]))
#if MIN_VERSION_base(4,12,0)
-- TODO orphan instances are bad
instance Monad m => MonadFail (Hedgehog.PropertyT m) where
fail _ = Hedgehog.failure
#endif