Add support for Prefer tx=rollback
This commit is contained in:
committed by
Steve Chavez
parent
698fac8ff2
commit
dbf99c6ac1
@@ -15,6 +15,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- #1559, No downtime when reloading the schema cache with SIGUSR1 - @steve-chavez
|
- #1559, No downtime when reloading the schema cache with SIGUSR1 - @steve-chavez
|
||||||
- #504, Add `log-level` config option. The admitted levels are: crit, error, warn and info - @steve-chavez
|
- #504, Add `log-level` config option. The admitted levels are: crit, error, warn and info - @steve-chavez
|
||||||
- #1607, Enable embedding through multiple views recursively - @wolfgangwalther
|
- #1607, Enable embedding through multiple views recursively - @wolfgangwalther
|
||||||
|
- #1598, Allow rollback of the transaction with Prefer tx=rollback - @wolfgangwalther
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -154,8 +154,10 @@ test-suite spec
|
|||||||
Feature.DeleteSpec
|
Feature.DeleteSpec
|
||||||
Feature.EmbedDisambiguationSpec
|
Feature.EmbedDisambiguationSpec
|
||||||
Feature.ExtraSearchPathSpec
|
Feature.ExtraSearchPathSpec
|
||||||
|
Feature.HtmlRawOutputSpec
|
||||||
Feature.InsertSpec
|
Feature.InsertSpec
|
||||||
Feature.JsonOperatorSpec
|
Feature.JsonOperatorSpec
|
||||||
|
Feature.MultipleSchemaSpec
|
||||||
Feature.NoJwtSpec
|
Feature.NoJwtSpec
|
||||||
Feature.NonexistentSchemaSpec
|
Feature.NonexistentSchemaSpec
|
||||||
Feature.OpenApiSpec
|
Feature.OpenApiSpec
|
||||||
@@ -164,6 +166,8 @@ test-suite spec
|
|||||||
Feature.QueryLimitedSpec
|
Feature.QueryLimitedSpec
|
||||||
Feature.QuerySpec
|
Feature.QuerySpec
|
||||||
Feature.RangeSpec
|
Feature.RangeSpec
|
||||||
|
Feature.RawOutputTypesSpec
|
||||||
|
Feature.RollbackSpec
|
||||||
Feature.RootSpec
|
Feature.RootSpec
|
||||||
Feature.RpcPreRequestGucsSpec
|
Feature.RpcPreRequestGucsSpec
|
||||||
Feature.RpcSpec
|
Feature.RpcSpec
|
||||||
@@ -171,9 +175,6 @@ test-suite spec
|
|||||||
Feature.UnicodeSpec
|
Feature.UnicodeSpec
|
||||||
Feature.UpdateSpec
|
Feature.UpdateSpec
|
||||||
Feature.UpsertSpec
|
Feature.UpsertSpec
|
||||||
Feature.RawOutputTypesSpec
|
|
||||||
Feature.HtmlRawOutputSpec
|
|
||||||
Feature.MultipleSchemaSpec
|
|
||||||
SpecHelper
|
SpecHelper
|
||||||
TestTypes
|
TestTypes
|
||||||
hs-source-dirs: test
|
hs-source-dirs: test
|
||||||
|
|||||||
+14
-10
@@ -114,6 +114,7 @@ data ApiRequest = ApiRequest {
|
|||||||
, iPreferParameters :: Maybe PreferParameters -- ^ How to pass parameters to a stored procedure
|
, iPreferParameters :: Maybe PreferParameters -- ^ How to pass parameters to a stored procedure
|
||||||
, iPreferCount :: Maybe PreferCount -- ^ Whether the client wants a result count
|
, iPreferCount :: Maybe PreferCount -- ^ Whether the client wants a result count
|
||||||
, iPreferResolution :: Maybe PreferResolution -- ^ Whether the client wants to UPSERT or ignore records on PK conflict
|
, iPreferResolution :: Maybe PreferResolution -- ^ Whether the client wants to UPSERT or ignore records on PK conflict
|
||||||
|
, iPreferTransaction :: Maybe PreferTransaction -- ^ Whether the clients wants to commit or rollback the transaction
|
||||||
, iFilters :: [(Text, Text)] -- ^ Filters on the result ("id", "eq.10")
|
, iFilters :: [(Text, Text)] -- ^ Filters on the result ("id", "eq.10")
|
||||||
, iLogic :: [(Text, Text)] -- ^ &and and &or parameters used for complex boolean logic
|
, iLogic :: [(Text, Text)] -- ^ &and and &or parameters used for complex boolean logic
|
||||||
, iSelect :: Maybe Text -- ^ &select parameter used to shape the response
|
, iSelect :: Maybe Text -- ^ &select parameter used to shape the response
|
||||||
@@ -146,16 +147,19 @@ userApiRequest confSchemas rootSpec dbStructure req reqBody
|
|||||||
, iAccepts = maybe [CTAny] (map decodeContentType . parseHttpAccept) $ lookupHeader "accept"
|
, iAccepts = maybe [CTAny] (map decodeContentType . parseHttpAccept) $ lookupHeader "accept"
|
||||||
, iPayload = relevantPayload
|
, iPayload = relevantPayload
|
||||||
, iPreferRepresentation = representation
|
, iPreferRepresentation = representation
|
||||||
, iPreferParameters = if | hasPrefer (show SingleObject) -> Just SingleObject
|
, iPreferParameters = if | hasPrefer (show SingleObject) -> Just SingleObject
|
||||||
| hasPrefer (show MultipleObjects) -> Just MultipleObjects
|
| hasPrefer (show MultipleObjects) -> Just MultipleObjects
|
||||||
| otherwise -> Nothing
|
| otherwise -> Nothing
|
||||||
, iPreferCount = if | hasPrefer (show ExactCount) -> Just ExactCount
|
, iPreferCount = if | hasPrefer (show ExactCount) -> Just ExactCount
|
||||||
| hasPrefer (show PlannedCount) -> Just PlannedCount
|
| hasPrefer (show PlannedCount) -> Just PlannedCount
|
||||||
| hasPrefer (show EstimatedCount) -> Just EstimatedCount
|
| hasPrefer (show EstimatedCount) -> Just EstimatedCount
|
||||||
| otherwise -> Nothing
|
| otherwise -> Nothing
|
||||||
, iPreferResolution = if | hasPrefer (show MergeDuplicates) -> Just MergeDuplicates
|
, iPreferResolution = if | hasPrefer (show MergeDuplicates) -> Just MergeDuplicates
|
||||||
| hasPrefer (show IgnoreDuplicates) -> Just IgnoreDuplicates
|
| hasPrefer (show IgnoreDuplicates) -> Just IgnoreDuplicates
|
||||||
| otherwise -> Nothing
|
| otherwise -> Nothing
|
||||||
|
, iPreferTransaction = if | hasPrefer (show Commit) -> Just Commit
|
||||||
|
| hasPrefer (show Rollback) -> Just Rollback
|
||||||
|
| otherwise -> Nothing
|
||||||
, iFilters = filters
|
, iFilters = filters
|
||||||
, iLogic = [(toS k, toS $ fromJust v) | (k,v) <- qParams, isJust v, endingIn ["and", "or"] k ]
|
, iLogic = [(toS k, toS $ fromJust v) | (k,v) <- qParams, isJust v, endingIn ["and", "or"] k ]
|
||||||
, iSelect = toS <$> join (lookup "select" qParams)
|
, iSelect = toS <$> join (lookup "select" qParams)
|
||||||
|
|||||||
@@ -86,7 +86,15 @@ postgrest logLev refConf refDbStructure pool getTime connWorker =
|
|||||||
Right claims -> do
|
Right claims -> do
|
||||||
let
|
let
|
||||||
authed = containsRole claims
|
authed = containsRole claims
|
||||||
handleReq = runPgLocals conf claims (app dbStructure conf) apiRequest
|
shouldCommit = configTxAllowOverride conf && iPreferTransaction apiRequest == Just Commit
|
||||||
|
shouldRollback = configTxAllowOverride conf && iPreferTransaction apiRequest == Just Rollback
|
||||||
|
preferenceApplied
|
||||||
|
| shouldCommit = addHeadersIfNotIncluded [(hPreferenceApplied, BS.pack (show Commit))]
|
||||||
|
| shouldRollback = addHeadersIfNotIncluded [(hPreferenceApplied, BS.pack (show Rollback))]
|
||||||
|
| otherwise = identity
|
||||||
|
handleReq = do
|
||||||
|
when (shouldRollback || (configTxRollbackAll conf && not shouldCommit)) HT.condemn
|
||||||
|
mapResponseHeaders preferenceApplied <$> runPgLocals conf claims (app dbStructure conf) apiRequest
|
||||||
dbResp <- P.use pool $ HT.transaction HT.ReadCommitted (txMode apiRequest) handleReq
|
dbResp <- P.use pool $ HT.transaction HT.ReadCommitted (txMode apiRequest) handleReq
|
||||||
return $ either (errorResponseFor . PgError authed) identity dbResp
|
return $ either (errorResponseFor . PgError authed) identity dbResp
|
||||||
-- Launch the connWorker when the connection is down. The postgrest function can respond successfully(with a stale schema cache) before the connWorker is done.
|
-- Launch the connWorker when the connection is down. The postgrest function can respond successfully(with a stale schema cache) before the connWorker is done.
|
||||||
|
|||||||
+16
-2
@@ -97,6 +97,9 @@ data AppConfig = AppConfig {
|
|||||||
, configJWKS :: Maybe JWKSet
|
, configJWKS :: Maybe JWKSet
|
||||||
|
|
||||||
, configLogLevel :: LogLevel
|
, configLogLevel :: LogLevel
|
||||||
|
|
||||||
|
, configTxRollbackAll :: Bool
|
||||||
|
, configTxAllowOverride :: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
configPoolTimeout' :: (Fractional a) => AppConfig -> a
|
configPoolTimeout' :: (Fractional a) => AppConfig -> a
|
||||||
@@ -196,6 +199,15 @@ readPathShowHelp = customExecParser parserPrefs opts
|
|||||||
|
|
|
|
||||||
|## logging level, the admitted values are: crit, error, warn and info.
|
|## logging level, the admitted values are: crit, error, warn and info.
|
||||||
|# log-level = "error"
|
|# log-level = "error"
|
||||||
|
|
|
||||||
|
|## rollback all transactions by default, use for test environments
|
||||||
|
|## disabled by default
|
||||||
|
|# tx-rollback-all = false
|
||||||
|
|
|
||||||
|
|## allow overriding the tx-rollback-all setting for a request by
|
||||||
|
|## setting the Prefer: tx=[commit|rollback] header
|
||||||
|
|## disabled by default
|
||||||
|
|# tx-allow-override = false
|
||||||
|]
|
|]
|
||||||
|
|
||||||
-- | Parse the config file
|
-- | Parse the config file
|
||||||
@@ -225,9 +237,9 @@ readAppConfig cfgPath = do
|
|||||||
<*> (fmap unpack <$> optString "server-unix-socket")
|
<*> (fmap unpack <$> optString "server-unix-socket")
|
||||||
<*> parseSocketFileMode "server-unix-socket-mode"
|
<*> parseSocketFileMode "server-unix-socket-mode"
|
||||||
<*> (fromMaybe "pgrst" <$> optString "db-channel")
|
<*> (fromMaybe "pgrst" <$> optString "db-channel")
|
||||||
<*> ((Just True ==) <$> optBool "db-channel-enabled")
|
<*> (fromMaybe False <$> optBool "db-channel-enabled")
|
||||||
<*> (fmap encodeUtf8 <$> optString "jwt-secret")
|
<*> (fmap encodeUtf8 <$> optString "jwt-secret")
|
||||||
<*> ((Just True ==) <$> optBool "secret-is-base64")
|
<*> (fromMaybe False <$> optBool "secret-is-base64")
|
||||||
<*> parseJwtAudience "jwt-aud"
|
<*> parseJwtAudience "jwt-aud"
|
||||||
<*> (fromMaybe 10 <$> optInt "db-pool")
|
<*> (fromMaybe 10 <$> optInt "db-pool")
|
||||||
<*> (fromMaybe 10 <$> optInt "db-pool-timeout")
|
<*> (fromMaybe 10 <$> optInt "db-pool-timeout")
|
||||||
@@ -240,6 +252,8 @@ readAppConfig cfgPath = do
|
|||||||
<*> (maybe [] (fmap encodeUtf8 . splitOnCommas) <$> optValue "raw-media-types")
|
<*> (maybe [] (fmap encodeUtf8 . splitOnCommas) <$> optValue "raw-media-types")
|
||||||
<*> pure Nothing
|
<*> pure Nothing
|
||||||
<*> parseLogLevel "log-level"
|
<*> parseLogLevel "log-level"
|
||||||
|
<*> (fromMaybe False <$> optBool "tx-rollback-all")
|
||||||
|
<*> (fromMaybe False <$> optBool "tx-allow-override")
|
||||||
|
|
||||||
parseSocketFileMode :: C.Key -> C.Parser C.Config (Either Text FileMode)
|
parseSocketFileMode :: C.Key -> C.Parser C.Config (Either Text FileMode)
|
||||||
parseSocketFileMode k =
|
parseSocketFileMode k =
|
||||||
|
|||||||
@@ -109,6 +109,15 @@ instance Show PreferCount where
|
|||||||
show PlannedCount = "count=planned"
|
show PlannedCount = "count=planned"
|
||||||
show EstimatedCount = "count=estimated"
|
show EstimatedCount = "count=estimated"
|
||||||
|
|
||||||
|
data PreferTransaction
|
||||||
|
= Commit -- Commit transaction - the default.
|
||||||
|
| Rollback -- Rollback transaction after sending the response - does not persist changes, e.g. for running tests.
|
||||||
|
deriving Eq
|
||||||
|
|
||||||
|
instance Show PreferTransaction where
|
||||||
|
show Commit = "tx=commit"
|
||||||
|
show Rollback = "tx=rollback"
|
||||||
|
|
||||||
data DbStructure = DbStructure {
|
data DbStructure = DbStructure {
|
||||||
dbTables :: [Table]
|
dbTables :: [Table]
|
||||||
, dbColumns :: [Column]
|
, dbColumns :: [Column]
|
||||||
|
|||||||
@@ -0,0 +1,218 @@
|
|||||||
|
module Feature.RollbackSpec where
|
||||||
|
|
||||||
|
import Network.Wai (Application)
|
||||||
|
|
||||||
|
import Network.HTTP.Types
|
||||||
|
import Test.Hspec
|
||||||
|
import Test.Hspec.Wai
|
||||||
|
import Test.Hspec.Wai.JSON
|
||||||
|
|
||||||
|
import Protolude hiding (get)
|
||||||
|
import SpecHelper
|
||||||
|
|
||||||
|
-- two helpers functions to make sure that each test can setup and cleanup properly
|
||||||
|
|
||||||
|
-- creates Item to work with for PATCH and DELETE
|
||||||
|
postItem =
|
||||||
|
request methodPost "/items"
|
||||||
|
[("Prefer", "resolution=ignore-duplicates")]
|
||||||
|
[json|{"id":0}|]
|
||||||
|
`shouldRespondWith`
|
||||||
|
""
|
||||||
|
{ matchStatus = 201 }
|
||||||
|
|
||||||
|
-- removes Items left over from POST, PUT, and PATCH
|
||||||
|
deleteItems =
|
||||||
|
delete "/items?id=lte.0"
|
||||||
|
`shouldRespondWith`
|
||||||
|
""
|
||||||
|
{ matchStatus = 204 }
|
||||||
|
|
||||||
|
preferDefault = [("Prefer", "return=representation")]
|
||||||
|
preferCommit = [("Prefer", "return=representation"), ("Prefer", "tx=commit")]
|
||||||
|
preferRollback = [("Prefer", "return=representation"), ("Prefer", "tx=rollback")]
|
||||||
|
|
||||||
|
withoutPreferenceApplied = []
|
||||||
|
withPreferenceCommitApplied = [ "Preference-Applied" <:> "tx=commit" ]
|
||||||
|
withPreferenceRollbackApplied = [ "Preference-Applied" <:> "tx=rollback" ]
|
||||||
|
|
||||||
|
shouldRespondToReads reqHeaders respHeaders = do
|
||||||
|
it "responds to GET" $ do
|
||||||
|
request methodGet "/items?id=eq.1"
|
||||||
|
reqHeaders
|
||||||
|
""
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":1}]|]
|
||||||
|
{ matchHeaders = respHeaders }
|
||||||
|
|
||||||
|
it "responds to HEAD" $ do
|
||||||
|
request methodHead "/items?id=eq.1"
|
||||||
|
reqHeaders
|
||||||
|
""
|
||||||
|
`shouldRespondWith`
|
||||||
|
""
|
||||||
|
{ matchHeaders = respHeaders }
|
||||||
|
|
||||||
|
it "responds to GET on RPC" $ do
|
||||||
|
request methodGet "/rpc/search?id=1"
|
||||||
|
reqHeaders
|
||||||
|
""
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":1}]|]
|
||||||
|
{ matchHeaders = respHeaders }
|
||||||
|
|
||||||
|
it "responds to POST on RPC" $ do
|
||||||
|
request methodPost "/rpc/search"
|
||||||
|
reqHeaders
|
||||||
|
[json|{"id":1}|]
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":1}]|]
|
||||||
|
{ matchHeaders = respHeaders }
|
||||||
|
|
||||||
|
shouldPersistMutations reqHeaders respHeaders = do
|
||||||
|
it "does persist post" $ do
|
||||||
|
request methodPost "/items"
|
||||||
|
reqHeaders
|
||||||
|
[json|{"id":0}|]
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":0}]|]
|
||||||
|
{ matchStatus = 201
|
||||||
|
, matchHeaders = respHeaders }
|
||||||
|
get "items?id=eq.0"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":0}]|]
|
||||||
|
deleteItems
|
||||||
|
|
||||||
|
it "does persist put" $ do
|
||||||
|
request methodPut "/items?id=eq.0"
|
||||||
|
reqHeaders
|
||||||
|
[json|{"id":0}|]
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":0}]|]
|
||||||
|
{ matchHeaders = respHeaders }
|
||||||
|
get "items?id=eq.0"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":0}]|]
|
||||||
|
deleteItems
|
||||||
|
|
||||||
|
it "does persist patch" $ do
|
||||||
|
postItem
|
||||||
|
request methodPatch "/items?id=eq.0"
|
||||||
|
reqHeaders
|
||||||
|
[json|{"id":-1}|]
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":-1}]|]
|
||||||
|
{ matchHeaders = respHeaders }
|
||||||
|
get "items?id=eq.0"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[]|]
|
||||||
|
get "items?id=eq.-1"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":-1}]|]
|
||||||
|
deleteItems
|
||||||
|
|
||||||
|
it "does persist delete" $ do
|
||||||
|
postItem
|
||||||
|
request methodDelete "/items?id=eq.0"
|
||||||
|
reqHeaders
|
||||||
|
""
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":0}]|]
|
||||||
|
{ matchHeaders = respHeaders }
|
||||||
|
get "items?id=eq.0"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[]|]
|
||||||
|
|
||||||
|
shouldNotPersistMutations reqHeaders respHeaders = do
|
||||||
|
it "does not persist post" $ do
|
||||||
|
request methodPost "/items"
|
||||||
|
reqHeaders
|
||||||
|
[json|{"id":0}|]
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":0}]|]
|
||||||
|
{ matchStatus = 201
|
||||||
|
, matchHeaders = respHeaders }
|
||||||
|
get "items?id=eq.0"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[]|]
|
||||||
|
|
||||||
|
it "does not persist put" $ do
|
||||||
|
request methodPut "/items?id=eq.0"
|
||||||
|
reqHeaders
|
||||||
|
[json|{"id":0}|]
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":0}]|]
|
||||||
|
{ matchHeaders = respHeaders }
|
||||||
|
get "items?id=eq.0"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[]|]
|
||||||
|
|
||||||
|
it "does not persist patch" $ do
|
||||||
|
request methodPatch "/items?id=eq.1"
|
||||||
|
reqHeaders
|
||||||
|
[json|{"id":0}|]
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":0}]|]
|
||||||
|
{ matchHeaders = respHeaders }
|
||||||
|
get "items?id=eq.0"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[]|]
|
||||||
|
get "items?id=eq.1"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":1}]|]
|
||||||
|
|
||||||
|
it "does not persist delete" $ do
|
||||||
|
request methodDelete "/items?id=eq.1"
|
||||||
|
reqHeaders
|
||||||
|
""
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":1}]|]
|
||||||
|
{ matchHeaders = respHeaders }
|
||||||
|
get "items?id=eq.1"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{"id":1}]|]
|
||||||
|
|
||||||
|
allowed :: SpecWith ((), Application)
|
||||||
|
allowed = describe "tx-allow-override = true" $ do
|
||||||
|
describe "without Prefer tx" $ do
|
||||||
|
-- TODO: Change this to default to rollback for whole test-suite
|
||||||
|
preferDefault `shouldRespondToReads` withoutPreferenceApplied
|
||||||
|
preferDefault `shouldPersistMutations` withoutPreferenceApplied
|
||||||
|
|
||||||
|
describe "Prefer tx=commit" $ do
|
||||||
|
preferCommit `shouldRespondToReads` withPreferenceCommitApplied
|
||||||
|
preferCommit `shouldPersistMutations` withPreferenceCommitApplied
|
||||||
|
|
||||||
|
describe "Prefer tx=rollback" $ do
|
||||||
|
preferRollback `shouldRespondToReads` withPreferenceRollbackApplied
|
||||||
|
preferRollback `shouldNotPersistMutations` withPreferenceRollbackApplied
|
||||||
|
|
||||||
|
disallowed :: SpecWith ((), Application)
|
||||||
|
disallowed = describe "tx-rollback-all = false, tx-allow-override = false" $ do
|
||||||
|
describe "without Prefer tx" $ do
|
||||||
|
preferDefault `shouldRespondToReads` withoutPreferenceApplied
|
||||||
|
preferDefault `shouldPersistMutations` withoutPreferenceApplied
|
||||||
|
|
||||||
|
describe "Prefer tx=commit" $ do
|
||||||
|
preferCommit `shouldRespondToReads` withoutPreferenceApplied
|
||||||
|
preferCommit `shouldPersistMutations` withoutPreferenceApplied
|
||||||
|
|
||||||
|
describe "Prefer tx=rollback" $ do
|
||||||
|
preferRollback `shouldRespondToReads` withoutPreferenceApplied
|
||||||
|
preferRollback `shouldPersistMutations` withoutPreferenceApplied
|
||||||
|
|
||||||
|
|
||||||
|
forced :: SpecWith ((), Application)
|
||||||
|
forced = describe "tx-rollback-all = true, tx-allow-override = false" $ do
|
||||||
|
describe "without Prefer tx" $ do
|
||||||
|
preferDefault `shouldRespondToReads` withoutPreferenceApplied
|
||||||
|
preferDefault `shouldNotPersistMutations` withoutPreferenceApplied
|
||||||
|
|
||||||
|
describe "Prefer tx=commit" $ do
|
||||||
|
preferCommit `shouldRespondToReads` withoutPreferenceApplied
|
||||||
|
preferCommit `shouldNotPersistMutations` withoutPreferenceApplied
|
||||||
|
|
||||||
|
describe "Prefer tx=rollback" $ do
|
||||||
|
preferRollback `shouldRespondToReads` withoutPreferenceApplied
|
||||||
|
preferRollback `shouldNotPersistMutations` withoutPreferenceApplied
|
||||||
|
|
||||||
@@ -43,6 +43,7 @@ import qualified Feature.QueryLimitedSpec
|
|||||||
import qualified Feature.QuerySpec
|
import qualified Feature.QuerySpec
|
||||||
import qualified Feature.RangeSpec
|
import qualified Feature.RangeSpec
|
||||||
import qualified Feature.RawOutputTypesSpec
|
import qualified Feature.RawOutputTypesSpec
|
||||||
|
import qualified Feature.RollbackSpec
|
||||||
import qualified Feature.RootSpec
|
import qualified Feature.RootSpec
|
||||||
import qualified Feature.RpcPreRequestGucsSpec
|
import qualified Feature.RpcPreRequestGucsSpec
|
||||||
import qualified Feature.RpcSpec
|
import qualified Feature.RpcSpec
|
||||||
@@ -87,6 +88,8 @@ main = do
|
|||||||
rootSpecApp = app testCfgRootSpec
|
rootSpecApp = app testCfgRootSpec
|
||||||
htmlRawOutputApp = app testCfgHtmlRawOutput
|
htmlRawOutputApp = app testCfgHtmlRawOutput
|
||||||
responseHeadersApp = app testCfgResponseHeaders
|
responseHeadersApp = app testCfgResponseHeaders
|
||||||
|
disallowRollbackApp = app testCfgDisallowRollback
|
||||||
|
forceRollbackApp = app testCfgForceRollback
|
||||||
|
|
||||||
extraSearchPathApp = appDbs testCfgExtraSearchPath
|
extraSearchPathApp = appDbs testCfgExtraSearchPath
|
||||||
unicodeApp = appDbs testUnicodeCfg
|
unicodeApp = appDbs testUnicodeCfg
|
||||||
@@ -109,6 +112,7 @@ main = do
|
|||||||
, ("Feature.OptionsSpec" , Feature.OptionsSpec.spec)
|
, ("Feature.OptionsSpec" , Feature.OptionsSpec.spec)
|
||||||
, ("Feature.QuerySpec" , Feature.QuerySpec.spec actualPgVersion)
|
, ("Feature.QuerySpec" , Feature.QuerySpec.spec actualPgVersion)
|
||||||
, ("Feature.EmbedDisambiguationSpec" , Feature.EmbedDisambiguationSpec.spec)
|
, ("Feature.EmbedDisambiguationSpec" , Feature.EmbedDisambiguationSpec.spec)
|
||||||
|
, ("Feature.RollbackAllowedSpec" , Feature.RollbackSpec.allowed)
|
||||||
, ("Feature.RpcSpec" , Feature.RpcSpec.spec actualPgVersion)
|
, ("Feature.RpcSpec" , Feature.RpcSpec.spec actualPgVersion)
|
||||||
, ("Feature.AndOrParamsSpec" , Feature.AndOrParamsSpec.spec actualPgVersion)
|
, ("Feature.AndOrParamsSpec" , Feature.AndOrParamsSpec.spec actualPgVersion)
|
||||||
, ("Feature.UpsertSpec" , Feature.UpsertSpec.spec)
|
, ("Feature.UpsertSpec" , Feature.UpsertSpec.spec)
|
||||||
@@ -175,6 +179,13 @@ main = do
|
|||||||
before extraSearchPathApp $
|
before extraSearchPathApp $
|
||||||
describe "Feature.ExtraSearchPathSpec" Feature.ExtraSearchPathSpec.spec
|
describe "Feature.ExtraSearchPathSpec" Feature.ExtraSearchPathSpec.spec
|
||||||
|
|
||||||
|
-- this test runs with tx-rollback-all = false and tx-allow-override = false
|
||||||
|
before disallowRollbackApp $
|
||||||
|
describe "Feature.RollbackDisallowedSpec" Feature.RollbackSpec.disallowed
|
||||||
|
|
||||||
|
-- this test runs with tx-rollback-all = true and tx-allow-override = false
|
||||||
|
before forceRollbackApp $
|
||||||
|
describe "Feature.RollbackForcedSpec" Feature.RollbackSpec.forced
|
||||||
|
|
||||||
when (actualPgVersion >= pgVersion96) $ do
|
when (actualPgVersion >= pgVersion96) $ do
|
||||||
-- this test runs with a root spec function override
|
-- this test runs with a root spec function override
|
||||||
|
|||||||
@@ -90,11 +90,19 @@ _baseCfg = let secret = Just $ encodeUtf8 "reallyreallyreallyreallyverysafe" in
|
|||||||
, configRawMediaTypes = []
|
, configRawMediaTypes = []
|
||||||
, configJWKS = parseSecret <$> secret
|
, configJWKS = parseSecret <$> secret
|
||||||
, configLogLevel = LogCrit
|
, configLogLevel = LogCrit
|
||||||
|
, configTxRollbackAll = False
|
||||||
|
, configTxAllowOverride = True
|
||||||
}
|
}
|
||||||
|
|
||||||
testCfg :: Text -> AppConfig
|
testCfg :: Text -> AppConfig
|
||||||
testCfg testDbConn = _baseCfg { configDbUri = testDbConn }
|
testCfg testDbConn = _baseCfg { configDbUri = testDbConn }
|
||||||
|
|
||||||
|
testCfgDisallowRollback :: Text -> AppConfig
|
||||||
|
testCfgDisallowRollback testDbConn = (testCfg testDbConn) { configTxRollbackAll = False, configTxAllowOverride = False }
|
||||||
|
|
||||||
|
testCfgForceRollback :: Text -> AppConfig
|
||||||
|
testCfgForceRollback testDbConn = (testCfg testDbConn) { configTxRollbackAll = True, configTxAllowOverride = False }
|
||||||
|
|
||||||
testCfgNoJWT :: Text -> AppConfig
|
testCfgNoJWT :: Text -> AppConfig
|
||||||
testCfgNoJWT testDbConn = (testCfg testDbConn) { configJwtSecret = Nothing, configJWKS = Nothing }
|
testCfgNoJWT testDbConn = (testCfg testDbConn) { configJwtSecret = Nothing, configJWKS = Nothing }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user