hasql-queue-1.2.0.0: test/Hasql/Queue/TestUtils.hs
module Hasql.Queue.TestUtils where
import qualified Data.ByteString.Char8 as BSC
import Control.Concurrent.Async
import Database.Postgres.Temp as Temp
import Test.Hspec
import Control.Exception as E
import Data.Pool
import Hasql.Connection
import Hasql.Session
import qualified Data.ByteString.Base64.URL as Base64
import Control.Concurrent
import Data.IORef
import Data.Foldable
import Control.Monad ((<=<))
import Crypto.Hash.SHA1 (hash)
import Hasql.Queue.Migrate
aroundAll :: forall a. ((a -> IO ()) -> IO ()) -> SpecWith a -> Spec
aroundAll withFunc specWith = do
(var, stopper, asyncer) <- runIO $
(,,) <$> newEmptyMVar <*> newEmptyMVar <*> newIORef Nothing
let theStart :: IO a
theStart = do
thread <- async $ do
withFunc $ \x -> do
putMVar var x
takeMVar stopper
pure $ error "Don't evaluate this"
writeIORef asyncer $ Just thread
either pure pure =<< (wait thread `race` takeMVar var)
theStop :: a -> IO ()
theStop _ = do
putMVar stopper ()
traverse_ cancel =<< readIORef asyncer
beforeAll theStart $ afterAll theStop $ specWith
withConn :: Temp.DB -> (Connection -> IO a) -> IO a
withConn db f = do
let connStr = toConnectionString db
E.bracket (either (throwIO . userError . show) pure =<< acquire connStr) release f
withSetup :: (Pool Connection -> IO ()) -> IO ()
withSetup f = either throwIO pure <=< withDbCache $ \dbCache -> do
migratedConfig <- either throwIO pure =<<
cacheAction
(("~/.tmp-postgres/" <>) . BSC.unpack . Base64.encode . hash
$ BSC.pack $ migrationQueryString "int4")
(flip withConn $ flip migrate "int4")
(verboseConfig <> cacheConfig dbCache)
withConfig migratedConfig $ \db -> do
f =<< createPool
(either (throwIO . userError . show) pure =<< acquire (toConnectionString db))
release
2
60
50
withConnection :: (Connection -> IO ()) -> Pool Connection -> IO ()
withConnection = flip withResource
withConnection2 :: ((Connection, Connection) -> IO ()) -> Pool Connection -> IO ()
withConnection2 f pool = withResource pool $ \conn1 ->
withResource pool $ \conn2 -> f (conn1, conn2)
runImplicitTransaction :: Pool Connection -> Session a -> IO a
runImplicitTransaction pool action = do
let wrappedAction = do
r <- action
pure r
withResource pool $ \conn ->
either (throwIO . userError . show) pure =<< run wrappedAction conn
runReadCommitted :: Pool Connection -> Session a -> IO a
runReadCommitted = flip withReadCommitted
withReadCommitted :: Session a -> Pool Connection -> IO a
withReadCommitted action pool = do
let wrappedAction = do
sql "BEGIN"
r <- action
sql "ROLLBACK"
pure r
withResource pool $ \conn ->
either (throwIO . userError . show) pure =<< run wrappedAction conn