packages feed

migrant-postgresql-simple-0.1.0.0: test/Database/Migrant/Driver/PostgreSQL_Tests.hs

{-#LANGUAGE OverloadedStrings #-}
{-#LANGUAGE ScopedTypeVariables #-}
module Database.Migrant.Driver.PostgreSQL_Tests
( tests
)
where

import Test.Tasty
import Test.Tasty.QuickCheck
import Test.Tasty.HUnit
import Data.Text (Text)
import Control.Monad (void)
import System.Environment
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import qualified Database.PostgreSQL.Simple as PostgreSQL
import System.Process (callProcess)
import Control.Exception (catch, bracket)
import System.Random

import Database.Migrant
import Database.Migrant.Driver.PostgreSQL

tests :: TestTree
tests = testGroup "PostgreSQL"
  [ testCase "Setup/init" testPostgreSQLSetup
  , testCase "Up" testPostgreSQLUp
  , testCase "Down" testPostgreSQLDown
  ]

withTestDB :: (PostgreSQL.Connection -> IO a) -> IO a
withTestDB action = do
  i <- randomRIO (1000000, 9999999)
  let dbname = "_migrant_test_" <> show (i :: Int)
  callProcess "createdb" [dbname]
  let dsn = "dbname=" <> dbname
  bracket
    (PostgreSQL.connectPostgreSQL $ Text.encodeUtf8 . Text.pack $ dsn)
    (\conn -> do
        PostgreSQL.close conn
        callProcess "dropdb" [dbname] `catch` (\(e :: IOError) -> return ())
    )
    action

testPostgreSQLSetup :: Assertion
testPostgreSQLSetup = withTestDB $ \conn -> do
  migrate [] undefined undefined conn
  actual <- PostgreSQL.query_ conn "SELECT name FROM _migrations ORDER BY id"
  let expected = [] :: [PostgreSQL.Only Text]
  assertEqual "Migration table exists" expected actual

testPostgreSQLUp :: Assertion
testPostgreSQLUp = do
  let up "foo" conn =
        void $ PostgreSQL.execute_ conn "CREATE TABLE foo (id INTEGER PRIMARY KEY)"
      up name _ = error ("Invalid name " <> show name)
      down "foo" conn =
        void $ PostgreSQL.execute_ conn "DROP TABLE foo"
      down name _ = error ("Invalid name " <> show name)
  withTestDB $ \conn -> do
    migrate ["foo"] up down conn

    actual <- PostgreSQL.query_ conn "SELECT name FROM _migrations ORDER BY id"
    let expected = [PostgreSQL.Only ("foo" :: Text)]
    assertEqual "Up migration logged" expected actual

    actual <- PostgreSQL.query_ conn "SELECT COUNT(1) FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'foo'"
    let expected = [PostgreSQL.Only (1 :: Int)]
    assertEqual "Up migration happened" expected actual

testPostgreSQLDown :: Assertion
testPostgreSQLDown = do
  let up "foo" conn =
        void $ PostgreSQL.execute_ conn "CREATE TABLE foo (id INTEGER PRIMARY KEY)"
      up name _ = error ("Invalid name " <> show name)
      down "foo" conn =
        void $ PostgreSQL.execute_ conn "DROP TABLE foo"
      down name _ = error ("Invalid name " <> show name)

  withTestDB $ \conn -> do
    migrate ["foo"] up down conn
    migrate [] up down conn

    actual <- PostgreSQL.query_ conn "SELECT name FROM _migrations ORDER BY id"
    let expected = [] :: [PostgreSQL.Only Text]
    assertEqual "Down migration logged" expected actual

    actual <- PostgreSQL.query_ conn "SELECT COUNT(1) FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'foo'"
    let expected = [PostgreSQL.Only (0 :: Int)]
    assertEqual "Down migration happened" expected actual