hspec-pg-transact 0.1.0.2 → 0.1.0.3
raw patch · 5 files changed
+153/−24 lines, 5 filesdep +hspec-coredep +hspec-pg-transactnew-uploaderPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: hspec-core, hspec-pg-transact
API changes (from Hackage documentation)
+ Test.Hspec.DB: describeDBWithConfig :: Config -> (Connection -> IO ()) -> String -> SpecWith TestDB -> Spec
+ Test.Hspec.DB: setupDBWithConfig :: Config -> (Connection -> IO ()) -> IO (Either StartError TestDB)
+ Test.Hspec.DB: wrapCallback :: (Connection -> IO ()) -> DB -> IO TestDB
- Test.Hspec.DB: setupDB :: (Connection -> IO ()) -> IO TestDB
+ Test.Hspec.DB: setupDB :: (Connection -> IO ()) -> IO (Either StartError TestDB)
Files
- README.md +27/−1
- hspec-pg-transact.cabal +21/−3
- src/Test/Hspec/DB.hs +36/−20
- test/Hspec/DBSpec.hs +53/−0
- test/Spec.hs +16/−0
README.md view
@@ -1,1 +1,27 @@-# hspec-pg-transact+# hspec-pg-transact [](https://github.com/jfischoff/pg-transact-hspec/actions/workflows/ci.yml)++Helpers for creating database tests with hspec and pg-transact++hspec-pg-transact utilizes tmp-postgres to automatically and connect to a+temporary instance of postgres on a random port.++ ```haskell+describeDB migrate "Query" $+ itDB "work" $ do+ execute_ [sql|+ INSERT INTO things+ VALUES (‘me’) |]+ query_ [sql|+ SELECT name+ FROM things |]+ `shouldReturn` [Only "me"]+ ```++In the example above describeDB wraps describe with a beforeAll hook for+creating a db and a afterAll hook for stopping a db.++Tests can be written with itDB which is wrapper around it that uses the passed+in TestDB to run a db transaction automatically for the test.++The libary also provides a few other functions for more fine grained control+over running transactions in tests.
hspec-pg-transact.cabal view
@@ -1,5 +1,5 @@ name: hspec-pg-transact-version: 0.1.0.2+version: 0.1.0.3 synopsis: Helpers for creating database tests with hspec and pg-transact description: Helpers for creating database tests with hspec and pg-transact@@ -28,7 +28,7 @@ license-file: LICENSE author: Jonathan Fischoff maintainer: jonathangfischoff@gmail.com-copyright: 2017 Jonathan Fischoff+copyright: 2021 Jonathan Fischoff category: Web build-type: Simple extra-source-files: README.md@@ -45,8 +45,26 @@ , bytestring , text , resource-pool- default-language: Haskell2010+ default-language: Haskell2010 ghc-options: -Wall -Wno-unused-do-bind++test-suite test+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ other-modules:+ Hspec.DBSpec+ hs-source-dirs:+ test+ build-depends:+ base >= 4.7 && < 5+ , hspec-pg-transact+ , pg-transact+ , postgresql-simple+ , hspec+ , hspec-core+ , tmp-postgres+ default-language: Haskell2010+ ghc-options: -Wall -Wno-unused-do-bind -threaded -rtsopts -with-rtsopts=-N source-repository head type: git
src/Test/Hspec/DB.hs view
@@ -22,43 +22,50 @@ The libary also provides a few other functions for more fine grained control over running transactions in tests. -}-{-# LANGUAGE RecordWildCards #-}+ module Test.Hspec.DB where-import Control.Exception+ import Control.Monad-import qualified Data.ByteString.Char8 as BSC import Data.Pool-import qualified Database.Postgres.Temp as Temp import Database.PostgreSQL.Simple import Database.PostgreSQL.Transact+import qualified Database.Postgres.Temp as Temp import Test.Hspec data TestDB = TestDB- { tempDB :: Temp.DB+ { tempDB :: Temp.DB -- ^ Handle for temporary @postgres@ process- , pool :: Pool Connection+ , pool :: Pool Connection -- ^ Pool of 50 connections to the temporary @postgres@ } -- | Start a temporary @postgres@ process and create a pool of connections to it-setupDB :: (Connection -> IO ()) -> IO TestDB-setupDB migrate = do- tempDB <- either throwIO return =<< Temp.startAndLogToTmp []- putStrLn $ Temp.connectionString tempDB- pool <- createPool- (connectPostgreSQL (BSC.pack $ Temp.connectionString tempDB))+setupDB :: (Connection -> IO ()) -> IO (Either Temp.StartError TestDB)+setupDB = setupDBWithConfig Temp.defaultConfig++-- | Start a temporary @postgres@ process using the provided configuration+setupDBWithConfig :: Temp.Config+ -> (Connection -> IO ())+ -> IO (Either Temp.StartError TestDB)+setupDBWithConfig c f =+ traverse (wrapCallback f) =<< Temp.startConfig c++wrapCallback :: (Connection -> IO ()) -> Temp.DB -> IO TestDB+wrapCallback f d = do+ p <- createPool+ (connectPostgreSQL $ Temp.toConnectionString d) close 1 100000000 50- withResource pool migrate- return TestDB {..}+ withResource p f+ pure $ TestDB d p -- | Drop all the connections and shutdown the @postgres@ process teardownDB :: TestDB -> IO ()-teardownDB TestDB {..} = do- destroyAllResources pool- void $ Temp.stop tempDB+teardownDB (TestDB d p) = do+ destroyAllResources p+ void $ Temp.stop d -- | Run an 'IO' action with a connection from the pool withPool :: TestDB -> (Connection -> IO a) -> IO a@@ -78,6 +85,10 @@ itDB :: String -> DB a -> SpecWith TestDB itDB msg action = it msg $ void . withDB action +-- | Wraps 'describeDBWithConfig' using the default configuration+describeDB :: (Connection -> IO ()) -> String -> SpecWith TestDB -> Spec+describeDB = describeDBWithConfig Temp.defaultConfig+ -- | Wraps 'describe' with a -- -- @@@ -91,6 +102,11 @@ -- @ -- -- hook for stopping a db.-describeDB :: (Connection -> IO ()) -> String -> SpecWith TestDB -> Spec-describeDB migrate str =- beforeAll (setupDB migrate) . afterAll teardownDB . describe str+describeDBWithConfig :: Temp.Config -> (Connection -> IO ()) -> String -> SpecWith TestDB -> Spec+describeDBWithConfig c f s =+ beforeAll (catch =<< setupDBWithConfig c f) . afterAll teardownDB . describe s+ where+ catch :: Either Temp.StartError TestDB -> IO TestDB+ catch r = case r of+ Left x -> error (show x)+ Right db -> pure db
+ test/Hspec/DBSpec.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TypeApplications #-}+{-# OPTIONS_GHC -Wno-deferred-type-errors #-}++module Hspec.DBSpec where++import Control.Monad.IO.Class (MonadIO (liftIO))+import Data.Functor (void)+import Data.Monoid (Last (Last))+import Database.PostgreSQL.Simple (Only (..))+import Database.PostgreSQL.Simple.SqlQQ (sql)+import Database.PostgreSQL.Transact (DBT, execute, execute_,+ query_, runDBTSerializable)+import Database.Postgres.Temp (Config (port, postgresConfig),+ ProcessConfig (stdIn, stdOut),+ defaultConfig)+import System.IO (Handle)+import Test.Hspec (SpecWith, shouldBe)+import Test.Hspec.Core.Spec (Spec)+import Test.Hspec.DB (TestDB, describeDB,+ describeDBWithConfig, itDB)++defaultSpec :: Spec+defaultSpec =+ describeDB (runDBTSerializable migrate) "with default config" test++customSpec :: Handle -> Handle -> Spec+customSpec i o =+ describeDBWithConfig+ ( defaultConfig+ { postgresConfig =+ (postgresConfig defaultConfig)+ { stdIn = Last $ Just i,+ stdOut = Last $ Just o+ }+ , port = Last $ Just $ Just 8999+ }+ )+ (runDBTSerializable migrate)+ "with custom config"+ test++migrate :: DBT IO ()+migrate = void $ execute_ [sql| CREATE TABLE things (n VARCHAR NOT NULL) |]++test :: SpecWith TestDB+test =+ itDB "basic insert/select" $ do+ execute [sql| INSERT INTO things (n) VALUES (?) |] (Only name)+ name' <- query_ [sql| SELECT n FROM things |]+ liftIO $ name' `shouldBe` [Only name]+ where+ name = "dupont"
+ test/Spec.hs view
@@ -0,0 +1,16 @@+module Main where++import qualified Hspec.DBSpec+import System.IO+import Test.Hspec (Spec, describe, hspec)++main :: IO ()+main = do+ withFile "/tmp/pgto.log" AppendMode $+ hspec . spec stdin++spec :: Handle -> Handle -> Spec+spec i o = do+ describe "pg-transact-hspec" $ do+ Hspec.DBSpec.defaultSpec+ Hspec.DBSpec.customSpec i o