relocant-1.1.0: test/Relocant/ScriptSpec.hs
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TypeApplications #-}
module Relocant.ScriptSpec (spec) where
import Database.PostgreSQL.Simple (withTransaction)
import Prelude hiding (id)
import System.FilePath ((</>))
import System.IO.Temp
import Test.Hspec
import Relocant.App.Env qualified as Env
import Relocant.Script
( Script(..)
, parseFilePath
, readContent
, readScripts
, readScript
, apply
)
import SpecHelper.DB qualified as DB
spec :: Spec
spec = do
describe "parseFilePath" $ do
it "empty ID/name is an ID/name" $
parseFilePath ".sql" `shouldBe` ("", "")
it "parses a bare migration ID" $
parseFilePath "0001.sql" `shouldBe` ("0001", "0001")
it "parses a migration ID separated from the rest of the name" $
parseFilePath "0001-migration-name.sql" `shouldBe` ("0001", "0001-migration-name")
it "migration ID can be arbitrary (alphanumeric value)" $ do
parseFilePath "abc4-migration-name.sql" `shouldBe` ("abc4", "abc4-migration-name")
parseFilePath "a%&#-migration-name.sql" `shouldBe` ("a", "a%&#-migration-name")
it "the .sql extenstion is optional (but recommended (for your sanity))" $
parseFilePath "abc4-migration-name" `shouldBe` ("abc4", "abc4-migration-name")
describe "readContent" $ do
it "reads the file and returns the content and its hash" $
withSystemTempDirectory Env.name $ \tmpDir -> do
let
path =
tmpDir </> "a"
writeFile path "abc"
readContent path `shouldReturn` "abc"
describe "readScript" $ do
it "combines parseFilePath and readContent" $
withSystemTempDirectory Env.name $ \tmpDir -> do
let
path =
tmpDir </> "0001-migration-name.sql"
writeFile path "abc"
readScript path `shouldReturn`
Script
{ id = "0001"
, name = "0001-migration-name"
, content = "abc"
}
describe "readScripts" $
it "lists all .sql files in a directory, ordered by ID" $
withSystemTempDirectory Env.name $ \tmpDir -> do
let
file name =
tmpDir </> name
writeFile (file "01-abc.sql") "abc"
writeFile (file "02-def.sql") "def"
writeFile (file "00-oops.sql") "oops"
readScripts tmpDir `shouldReturn`
[ Script
{ id = "00"
, name = "00-oops"
, content = "oops"
}
, Script
{ id = "01"
, name = "01-abc"
, content = "abc"
}
, Script
{ id = "02"
, name = "02-def"
, content = "def"
}
]
around DB.withTemplateCloned $ do
describe "apply" $ do
it "runs a migration script" $ \conn -> do
let
script = Script
{ id = "00"
, name = "00-oops"
, content = "CREATE TABLE foo ()"
}
withTransaction conn $ do
_durationS <- apply script conn
pure ()
context "empty script" $
it "runs a migration script" $ \conn -> do
let
script = Script
{ id = "00"
, name = "00-oops"
, content = ""
}
withTransaction conn $ do
_durationS <- apply script conn
pure ()