packages feed

sydtest-sqitch-postgres-0.1.1.0: test/Test/Syd/Sqitch/PostgresqlSpec.hs

{-# LANGUAGE GADTs #-}
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Test.Syd.Sqitch.PostgresqlSpec (spec) where

import Data.Text (Text)
import Path
import Path.IO
import Test.Syd
import Test.Syd.OptParse (Settings (..), Timeout (..), defaultSettings)
import Test.Syd.Persistent.Postgresql (emptyPostgresOptionsSetupFunc)
import Test.Syd.Sqitch.Postgresql

-- | Locate the sqitch executable on @PATH@ at test-suite start.
locateSqitch :: IO (Path Abs File)
locateSqitch = do
  m <- findExecutable [relfile|sqitch|]
  case m of
    Nothing -> fail "sqitch not found on PATH"
    Just p -> pure p

settingsFor :: Path Rel Dir -> Maybe Text -> IO SqitchSettings
settingsFor relDir mTag = do
  projectDir <- makeAbsolute relDir
  binPath <- locateSqitch
  pure
    SqitchSettings
      { sqitchSettingsProjectDir = projectDir,
        sqitchSettingsBin = binPath,
        sqitchSettingsGrandfatherTag = mTag
      }

spec :: Spec
spec = sequential $ do
  describe "sqitchPostgresqlSpec" $ do
    -- Both tests do work proportional to the number of changes, so a
    -- fixed budget would shrink as the plan grows.
    it "gives the sqitch tests a timeout that scales with the number of changes" $ do
      settings <- settingsFor [reldir|test_resources/toy-sqitch-ok|] Nothing
      forest <-
        execTestDefM (defaultSettings {settingRandomiseExecutionOrder = False}) $
          sqitchPostgresqlSpec settings
      -- Both tests have to be inside the node, not merely beside it.
      case forest of
        [ DefDescribeNode
            _
            [ DefTimeoutNode
                scaleTimeout
                [DefSpecifyNode _ _ _, DefSpecifyNode _ _ _]
              ]
          ] ->
            map scaleTimeout [DoNotTimeout, TimeoutAfterMicros 1_000_000]
              `shouldBe` [DoNotTimeout, TimeoutAfterMicros 3_000_000]
        _ -> expectationFailure "expected both sqitch tests to sit under a timeout node"

    describe "toy-sqitch-ok" $ do
      settings <- runIO $ settingsFor [reldir|test_resources/toy-sqitch-ok|] Nothing
      sqitchPostgresqlSpec settings

    describe "toy-sqitch-grandfathered with grandfather tag" $ do
      settings <-
        runIO $ settingsFor [reldir|test_resources/toy-sqitch-grandfathered|] (Just "legacy")
      sqitchPostgresqlSpec settings

  describe "negative cases" $
    expectFailing $ do
      describe "toy-sqitch-non-idempotent" $
        setupAround emptyPostgresOptionsSetupFunc $
          it "fails because the change is non-idempotent" $ \opts -> do
            settings <- settingsFor [reldir|test_resources/toy-sqitch-non-idempotent|] Nothing
            runSqitchPerChangeChecks settings opts

      describe "toy-sqitch-broken-revert" $
        setupAround emptyPostgresOptionsSetupFunc $
          it "fails because the revert is not the inverse of the deploy" $ \opts -> do
            settings <- settingsFor [reldir|test_resources/toy-sqitch-broken-revert|] Nothing
            runSqitchPerChangeChecks settings opts

      describe "toy-sqitch-grandfathered without grandfather tag" $
        setupAround emptyPostgresOptionsSetupFunc $
          it "fails because the pre-tag legacy change is no longer exempt" $ \opts -> do
            settings <- settingsFor [reldir|test_resources/toy-sqitch-grandfathered|] Nothing
            runSqitchPerChangeChecks settings opts

      describe "toy-sqitch-hardcoded-public" $
        setupAround emptyPostgresOptionsSetupFunc $
          it "fails because a verify hardcodes the public schema (caught by deploying into a non-public schema)" $ \opts -> do
            settings <- settingsFor [reldir|test_resources/toy-sqitch-hardcoded-public|] Nothing
            runSqitchPerChangeChecks settings opts